aboutsummaryrefslogtreecommitdiff
path: root/lldb
diff options
context:
space:
mode:
Diffstat (limited to 'lldb')
-rw-r--r--lldb/bindings/interface/SBSection.i4
-rw-r--r--lldb/bindings/interface/SBTrace.i2
-rw-r--r--lldb/include/lldb/API/SBSection.h6
-rw-r--r--lldb/include/lldb/API/SBTrace.h22
-rw-r--r--lldb/include/lldb/Core/Disassembler.h17
-rw-r--r--lldb/include/lldb/Expression/DWARFExpression.h128
-rw-r--r--lldb/include/lldb/Expression/DWARFExpressionList.h151
-rw-r--r--lldb/include/lldb/Interpreter/CommandObject.h3
-rw-r--r--lldb/include/lldb/Symbol/Function.h16
-rw-r--r--lldb/include/lldb/Symbol/ObjectFile.h2
-rw-r--r--lldb/include/lldb/Symbol/TypeList.h7
-rw-r--r--lldb/include/lldb/Symbol/TypeMap.h8
-rw-r--r--lldb/include/lldb/Symbol/Variable.h14
-rw-r--r--lldb/include/lldb/Target/StackFrame.h4
-rw-r--r--lldb/include/lldb/Target/Trace.h26
-rw-r--r--lldb/include/lldb/Target/TraceCursor.h10
-rw-r--r--lldb/include/lldb/Target/TraceDumper.h3
-rw-r--r--lldb/include/lldb/Utility/Environment.h2
-rw-r--r--lldb/include/lldb/Utility/RangeMap.h4
-rw-r--r--lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h5
-rw-r--r--lldb/include/lldb/lldb-enumerations.h47
-rw-r--r--lldb/include/lldb/lldb-forward.h1
-rw-r--r--lldb/source/API/SBInstruction.cpp7
-rw-r--r--lldb/source/API/SBInstructionList.cpp5
-rw-r--r--lldb/source/API/SBSection.cpp9
-rw-r--r--lldb/source/API/SBTrace.cpp18
-rw-r--r--lldb/source/Commands/CommandObjectDisassemble.cpp8
-rw-r--r--lldb/source/Commands/CommandObjectDisassemble.h1
-rw-r--r--lldb/source/Commands/CommandObjectProcess.cpp128
-rw-r--r--lldb/source/Commands/CommandObjectTarget.cpp69
-rw-r--r--lldb/source/Commands/CommandObjectThread.cpp33
-rw-r--r--lldb/source/Commands/CommandObjectTrace.cpp116
-rw-r--r--lldb/source/Commands/Options.td28
-rw-r--r--lldb/source/Core/Debugger.cpp15
-rw-r--r--lldb/source/Core/Disassembler.cpp376
-rw-r--r--lldb/source/Core/DumpDataExtractor.cpp5
-rw-r--r--lldb/source/Core/Module.cpp19
-rw-r--r--lldb/source/Core/ValueObjectVariable.cpp19
-rw-r--r--lldb/source/Expression/DWARFExpression.cpp334
-rw-r--r--lldb/source/Expression/DWARFExpressionList.cpp248
-rw-r--r--lldb/source/Expression/IRExecutionUnit.cpp4
-rw-r--r--lldb/source/Expression/Materializer.cpp2
-rw-r--r--lldb/source/Interpreter/CommandObject.cpp21
-rw-r--r--lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h11
-rw-r--r--lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp6
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp53
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h4
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp8
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp279
-rw-r--r--lldb/source/Plugins/Language/CPlusPlus/LibCxx.h50
-rw-r--r--lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp208
-rw-r--r--lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h22
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp3
-rw-r--r--lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp2
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp4
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h11
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp19
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp11
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h2
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp83
-rw-r--r--lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h1
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp4
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp10
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h4
-rw-r--r--lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp28
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp2
-rw-r--r--lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp7
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp89
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h18
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp32
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/DecodedThread.h23
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp2
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp45
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h5
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TaskTimer.h4
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp5
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp4
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h2
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp175
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h23
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.cpp138
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.h12
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h1
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp77
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h16
-rw-r--r--lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td29
-rw-r--r--lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp6
-rw-r--r--lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp4
-rw-r--r--lldb/source/Symbol/Function.cpp14
-rw-r--r--lldb/source/Symbol/Symbol.cpp5
-rw-r--r--lldb/source/Symbol/TypeList.cpp9
-rw-r--r--lldb/source/Symbol/TypeMap.cpp41
-rw-r--r--lldb/source/Symbol/Variable.cpp30
-rw-r--r--lldb/source/Target/RegisterContextUnwind.cpp20
-rw-r--r--lldb/source/Target/StackFrame.cpp10
-rw-r--r--lldb/source/Target/ThreadPlanTracer.cpp5
-rw-r--r--lldb/source/Target/TraceCursor.cpp3
-rw-r--r--lldb/source/Target/TraceDumper.cpp105
-rw-r--r--lldb/source/Utility/Args.cpp1
-rw-r--r--lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp12
104 files changed, 2591 insertions, 1161 deletions
diff --git a/lldb/bindings/interface/SBSection.i b/lldb/bindings/interface/SBSection.i
index b86d4e99c5ea..a138d81825b5 100644
--- a/lldb/bindings/interface/SBSection.i
+++ b/lldb/bindings/interface/SBSection.i
@@ -105,6 +105,9 @@ public:
uint32_t
GetTargetByteSize ();
+ uint32_t
+ GetAlignment ();
+
bool
GetDescription (lldb::SBStream &description);
@@ -138,6 +141,7 @@ public:
data = property(GetSectionData, None, doc='''A read only property that returns an lldb object that represents the bytes for this section (lldb.SBData) for this section.''')
type = property(GetSectionType, None, doc='''A read only property that returns an lldb enumeration value (see enumerations that start with "lldb.eSectionType") that represents the type of this section (code, data, etc.).''')
target_byte_size = property(GetTargetByteSize, None, doc='''A read only property that returns the size of a target byte represented by this section as a number of host bytes.''')
+ alignment = property(GetAlignment, None, doc='''A read only property that returns the alignment of this section as a number of host bytes.''')
%}
#endif
diff --git a/lldb/bindings/interface/SBTrace.i b/lldb/bindings/interface/SBTrace.i
index 0f5bf0ecc8d9..0d74881a3f3d 100644
--- a/lldb/bindings/interface/SBTrace.i
+++ b/lldb/bindings/interface/SBTrace.i
@@ -17,6 +17,8 @@ public:
const char *GetStartConfigurationHelp();
+ SBFileSpec SaveToDisk(SBError &error, const SBFileSpec &bundle_dir, bool compact = false);
+
SBError Start(const SBStructuredData &configuration);
SBError Start(const SBThread &thread, const SBStructuredData &configuration);
diff --git a/lldb/include/lldb/API/SBSection.h b/lldb/include/lldb/API/SBSection.h
index d722dbe4ff1f..94c6614ecfa9 100644
--- a/lldb/include/lldb/API/SBSection.h
+++ b/lldb/include/lldb/API/SBSection.h
@@ -76,6 +76,12 @@ public:
/// The number of host (8-bit) bytes needed to hold a target byte
uint32_t GetTargetByteSize();
+ /// Return the alignment of the section in bytes
+ ///
+ /// \return
+ /// The alignment of the section in bytes
+ uint32_t GetAlignment();
+
bool operator==(const lldb::SBSection &rhs);
bool operator!=(const lldb::SBSection &rhs);
diff --git a/lldb/include/lldb/API/SBTrace.h b/lldb/include/lldb/API/SBTrace.h
index d5cf30f56637..19d759013955 100644
--- a/lldb/include/lldb/API/SBTrace.h
+++ b/lldb/include/lldb/API/SBTrace.h
@@ -25,6 +25,28 @@ public:
static SBTrace LoadTraceFromFile(SBError &error, SBDebugger &debugger,
const SBFileSpec &trace_description_file);
+ /// Save the trace to the specified directory, which will be created if
+ /// needed. This will also create a a file \a <directory>/trace.json with the
+ /// main properties of the trace session, along with others files which
+ /// contain the actual trace data. The trace.json file can be used later as
+ /// input for the "trace load" command to load the trace in LLDB, or for the
+ /// method \a SBDebugger.LoadTraceFromFile().
+ ///
+ /// \param[out] error
+ /// This will be set with an error in case of failures.
+ ///
+ /// \param[in] directory
+ /// The directory where the trace files will be saved.
+ ///
+ /// \param[in] compact
+ /// Try not to save to disk information irrelevant to the traced processes.
+ /// Each trace plug-in implements this in a different fashion.
+ ///
+ /// \return
+ /// A \a SBFileSpec pointing to the bundle description file.
+ SBFileSpec SaveToDisk(SBError &error, const SBFileSpec &bundle_dir,
+ bool compact = false);
+
/// \return
/// A description of the parameters to use for the \a SBTrace::Start
/// method, or \b null if the object is invalid.
diff --git a/lldb/include/lldb/Core/Disassembler.h b/lldb/include/lldb/Core/Disassembler.h
index 2dd1153031a6..2cb983c40d19 100644
--- a/lldb/include/lldb/Core/Disassembler.h
+++ b/lldb/include/lldb/Core/Disassembler.h
@@ -79,6 +79,12 @@ public:
return m_comment.c_str();
}
+ /// \return
+ /// The control flow kind of this instruction, or
+ /// eInstructionControlFlowKindUnknown if the instruction
+ /// can't be classified.
+ lldb::InstructionControlFlowKind GetControlFlowKind(const ArchSpec &arch);
+
virtual void
CalculateMnemonicOperandsAndComment(const ExecutionContext *exe_ctx) = 0;
@@ -105,6 +111,9 @@ public:
/// \param[in] show_bytes
/// Whether the bytes of the assembly instruction should be printed.
///
+ /// \param[in] show_control_flow_kind
+ /// Whether the control flow kind of the instruction should be printed.
+ ///
/// \param[in] max_opcode_byte_size
/// The size (in bytes) of the largest instruction in the list that
/// we are printing (for text justification/alignment purposes)
@@ -140,7 +149,8 @@ public:
/// so this method can properly align the instruction opcodes.
/// May be 0 to indicate no indentation/alignment of the opcodes.
virtual void Dump(Stream *s, uint32_t max_opcode_byte_size, bool show_address,
- bool show_bytes, const ExecutionContext *exe_ctx,
+ bool show_bytes, bool show_control_flow_kind,
+ const ExecutionContext *exe_ctx,
const SymbolContext *sym_ctx,
const SymbolContext *prev_sym_ctx,
const FormatEntity::Entry *disassembly_addr_format,
@@ -320,7 +330,7 @@ public:
void Append(lldb::InstructionSP &inst_sp);
void Dump(Stream *s, bool show_address, bool show_bytes,
- const ExecutionContext *exe_ctx);
+ bool show_control_flow_kind, const ExecutionContext *exe_ctx);
private:
typedef std::vector<lldb::InstructionSP> collection;
@@ -375,7 +385,8 @@ public:
eOptionMarkPCSourceLine = (1u << 2), // Mark the source line that contains
// the current PC (mixed mode only)
eOptionMarkPCAddress =
- (1u << 3) // Mark the disassembly line the contains the PC
+ (1u << 3), // Mark the disassembly line the contains the PC
+ eOptionShowControlFlowKind = (1u << 4),
};
enum HexImmediateStyle {
diff --git a/lldb/include/lldb/Expression/DWARFExpression.h b/lldb/include/lldb/Expression/DWARFExpression.h
index 96a0e8e02da1..49e51d51f211 100644
--- a/lldb/include/lldb/Expression/DWARFExpression.h
+++ b/lldb/include/lldb/Expression/DWARFExpression.h
@@ -42,49 +42,14 @@ public:
/// \param[in] data
/// A data extractor configured to read the DWARF location expression's
/// bytecode.
- DWARFExpression(lldb::ModuleSP module, const DataExtractor &data,
- const DWARFUnit *dwarf_cu);
+ DWARFExpression(const DataExtractor &data);
/// Destructor
virtual ~DWARFExpression();
- /// Print the description of the expression to a stream
- ///
- /// \param[in] s
- /// The stream to print to.
- ///
- /// \param[in] level
- /// The level of verbosity to use.
- ///
- /// \param[in] abi
- /// An optional ABI plug-in that can be used to resolve register
- /// names.
- void GetDescription(Stream *s, lldb::DescriptionLevel level, ABI *abi) const;
-
/// Return true if the location expression contains data
bool IsValid() const;
- /// Return true if a location list was provided
- bool IsLocationList() const;
-
- /// Search for a load address in the location list
- ///
- /// \param[in] func_load_addr
- /// The actual address of the function containing this location list.
- ///
- /// \param[in] addr
- /// The address to resolve
- ///
- /// \return
- /// True if IsLocationList() is true and the address was found;
- /// false otherwise.
- // bool
- // LocationListContainsLoadAddress (Process* process, const Address &addr)
- // const;
- //
- bool LocationListContainsAddress(lldb::addr_t func_load_addr,
- lldb::addr_t addr) const;
-
/// If a location is not a location list, return true if the location
/// contains a DW_OP_addr () opcode in the stream that matches \a file_addr.
/// If file_addr is LLDB_INVALID_ADDRESS, the this function will return true
@@ -93,6 +58,9 @@ public:
/// static variable since there is no other indication from DWARF debug
/// info.
///
+ /// \param[in] dwarf_cu
+ /// The dwarf unit this expression belongs to.
+ ///
/// \param[in] op_addr_idx
/// The DW_OP_addr index to retrieve in case there is more than
/// one DW_OP_addr opcode in the location byte stream.
@@ -104,36 +72,22 @@ public:
/// \return
/// LLDB_INVALID_ADDRESS if the location doesn't contain a
/// DW_OP_addr for \a op_addr_idx, otherwise a valid file address
- lldb::addr_t GetLocation_DW_OP_addr(uint32_t op_addr_idx, bool &error) const;
+ lldb::addr_t GetLocation_DW_OP_addr(const DWARFUnit *dwarf_cu,
+ uint32_t op_addr_idx, bool &error) const;
bool Update_DW_OP_addr(lldb::addr_t file_addr);
void UpdateValue(uint64_t const_value, lldb::offset_t const_value_byte_size,
uint8_t addr_byte_size);
- void SetModule(const lldb::ModuleSP &module) { m_module_wp = module; }
-
bool ContainsThreadLocalStorage() const;
bool LinkThreadLocalStorage(
- lldb::ModuleSP new_module_sp,
std::function<lldb::addr_t(lldb::addr_t file_addr)> const
&link_address_callback);
- /// Tells the expression that it refers to a location list.
- ///
- /// \param[in] cu_file_addr
- /// The base address to use for interpreting relative location list
- /// entries.
- /// \param[in] func_file_addr
- /// The file address of the function containing this location list. This
- /// address will be used to relocate the location list on the fly (in
- /// conjuction with the func_load_addr arguments).
- void SetLocationListAddresses(lldb::addr_t cu_file_addr,
- lldb::addr_t func_file_addr);
-
/// Return the call-frame-info style register kind
- int GetRegisterKind();
+ lldb::RegisterKind GetRegisterKind() const;
/// Set the call-frame-info style register kind
///
@@ -141,20 +95,6 @@ public:
/// The register kind.
void SetRegisterKind(lldb::RegisterKind reg_kind);
- /// Wrapper for the static evaluate function that accepts an
- /// ExecutionContextScope instead of an ExecutionContext and uses member
- /// variables to populate many operands
- bool Evaluate(ExecutionContextScope *exe_scope, lldb::addr_t func_load_addr,
- const Value *initial_value_ptr, const Value *object_address_ptr,
- Value &result, Status *error_ptr) const;
-
- /// Wrapper for the static evaluate function that uses member variables to
- /// populate many operands
- bool Evaluate(ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
- lldb::addr_t loclist_base_load_addr,
- const Value *initial_value_ptr, const Value *object_address_ptr,
- Value &result, Status *error_ptr) const;
-
/// Evaluate a DWARF location expression in a particular context
///
/// \param[in] exe_ctx
@@ -194,72 +134,32 @@ public:
/// True on success; false otherwise. If error_ptr is non-NULL,
/// details of the failure are provided through it.
static bool Evaluate(ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
- lldb::ModuleSP opcode_ctx, const DataExtractor &opcodes,
+ lldb::ModuleSP module_sp, const DataExtractor &opcodes,
const DWARFUnit *dwarf_cu,
const lldb::RegisterKind reg_set,
const Value *initial_value_ptr,
const Value *object_address_ptr, Value &result,
Status *error_ptr);
+ static bool ParseDWARFLocationList(const DWARFUnit *dwarf_cu,
+ const DataExtractor &data,
+ DWARFExpressionList *loc_list);
+
bool GetExpressionData(DataExtractor &data) const {
data = m_data;
return data.GetByteSize() > 0;
}
- bool DumpLocationForAddress(Stream *s, lldb::DescriptionLevel level,
- lldb::addr_t func_load_addr, lldb::addr_t address,
- ABI *abi);
-
- bool DumpLocations(Stream *s, lldb::DescriptionLevel level,
- lldb::addr_t func_load_addr, lldb::addr_t addr, ABI *abi);
-
- bool GetLocationExpressions(
- lldb::addr_t load_function_start,
- llvm::function_ref<bool(llvm::DWARFLocationExpression)> callback) const;
+ void DumpLocation(Stream *s, lldb::DescriptionLevel level, ABI *abi) const;
- bool MatchesOperand(StackFrame &frame, const Instruction::Operand &op);
-
- llvm::Optional<DataExtractor>
- GetLocationExpression(lldb::addr_t load_function_start,
- lldb::addr_t addr) const;
+ bool MatchesOperand(StackFrame &frame, const Instruction::Operand &op) const;
private:
- /// Pretty-prints the location expression to a stream
- ///
- /// \param[in] s
- /// The stream to use for pretty-printing.
- ///
- /// \param[in] data
- /// The data extractor.
- ///
- /// \param[in] level
- /// The level of detail to use in pretty-printing.
- ///
- /// \param[in] abi
- /// An optional ABI plug-in that can be used to resolve register
- /// names.
- void DumpLocation(Stream *s, const DataExtractor &data,
- lldb::DescriptionLevel level, ABI *abi) const;
-
- /// Module which defined this expression.
- lldb::ModuleWP m_module_wp;
-
/// A data extractor capable of reading opcode bytes
DataExtractor m_data;
- /// The DWARF compile unit this expression belongs to. It is used to evaluate
- /// values indexing into the .debug_addr section (e.g. DW_OP_GNU_addr_index,
- /// DW_OP_GNU_const_index)
- const DWARFUnit *m_dwarf_cu = nullptr;
-
/// One of the defines that starts with LLDB_REGKIND_
lldb::RegisterKind m_reg_kind = lldb::eRegisterKindDWARF;
-
- struct LoclistAddresses {
- lldb::addr_t cu_file_addr;
- lldb::addr_t func_file_addr;
- };
- llvm::Optional<LoclistAddresses> m_loclist_addresses;
};
} // namespace lldb_private
diff --git a/lldb/include/lldb/Expression/DWARFExpressionList.h b/lldb/include/lldb/Expression/DWARFExpressionList.h
new file mode 100644
index 000000000000..a8f2a7126e3c
--- /dev/null
+++ b/lldb/include/lldb/Expression/DWARFExpressionList.h
@@ -0,0 +1,151 @@
+//===-- DWARFExpressionList.h -----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_EXPRESSION_DWARFEXPRESSIONLIST_H
+#define LLDB_EXPRESSION_DWARFEXPRESSIONLIST_H
+
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Utility/RangeMap.h"
+#include "lldb/lldb-private.h"
+#include "llvm/ADT/Optional.h"
+
+class DWARFUnit;
+
+namespace lldb_private {
+
+/// \class DWARFExpressionList DWARFExpressionList.h
+/// "lldb/Expression/DWARFExpressionList.h" Encapsulates a range map from file
+/// address range to a single DWARF location expression.
+class DWARFExpressionList {
+public:
+ DWARFExpressionList() = default;
+
+ DWARFExpressionList(lldb::ModuleSP module_sp, const DWARFUnit *dwarf_cu,
+ lldb::addr_t func_file_addr)
+ : m_module_wp(module_sp), m_dwarf_cu(dwarf_cu),
+ m_func_file_addr(func_file_addr) {}
+
+ DWARFExpressionList(lldb::ModuleSP module_sp, DWARFExpression expr,
+ const DWARFUnit *dwarf_cu)
+ : m_module_wp(module_sp), m_dwarf_cu(dwarf_cu) {
+ AddExpression(0, LLDB_INVALID_ADDRESS, expr);
+ }
+
+ /// Return true if the location expression contains data
+ bool IsValid() const { return !m_exprs.IsEmpty(); }
+
+ void Clear() { m_exprs.Clear(); }
+
+ // Return true if the location expression is always valid.
+ bool IsAlwaysValidSingleExpr() const;
+
+ bool AddExpression(lldb::addr_t base, lldb::addr_t end, DWARFExpression expr);
+
+ /// Get the expression data at the file address.
+ bool GetExpressionData(DataExtractor &data,
+ lldb::addr_t func_load_addr = LLDB_INVALID_ADDRESS,
+ lldb::addr_t file_addr = 0) const;
+
+ /// Sort m_expressions.
+ void Sort() { m_exprs.Sort(); }
+
+ void SetFuncFileAddress(lldb::addr_t func_file_addr) {
+ m_func_file_addr = func_file_addr;
+ }
+
+ lldb::addr_t GetFuncFileAddress() { return m_func_file_addr; }
+
+ const DWARFExpression *GetExpressionAtAddress(lldb::addr_t func_load_addr,
+ lldb::addr_t load_addr) const;
+
+ const DWARFExpression *GetAlwaysValidExpr() const;
+
+ DWARFExpression *GetMutableExpressionAtAddress(
+ lldb::addr_t func_load_addr = LLDB_INVALID_ADDRESS,
+ lldb::addr_t load_addr = 0);
+
+ size_t GetSize() const { return m_exprs.GetSize(); }
+
+ bool ContainsThreadLocalStorage() const;
+
+ bool LinkThreadLocalStorage(
+ lldb::ModuleSP new_module_sp,
+ std::function<lldb::addr_t(lldb::addr_t file_addr)> const
+ &link_address_callback);
+
+ bool MatchesOperand(StackFrame &frame,
+ const Instruction::Operand &operand) const;
+
+ /// Dump locations that contains file_addr if it's valid. Otherwise. dump all
+ /// locations.
+ bool DumpLocations(Stream *s, lldb::DescriptionLevel level,
+ lldb::addr_t func_load_addr, lldb::addr_t file_addr,
+ ABI *abi) const;
+
+ /// Dump all locaitons with each seperated by new line.
+ void GetDescription(Stream *s, lldb::DescriptionLevel level, ABI *abi) const;
+
+ /// Search for a load address in the dwarf location list
+ ///
+ /// \param[in] func_load_addr
+ /// The actual address of the function containing this location list.
+ ///
+ /// \param[in] addr
+ /// The address to resolve.
+ ///
+ /// \return
+ /// True if IsLocationList() is true and the address was found;
+ /// false otherwise.
+ // bool
+ // LocationListContainsLoadAddress (Process* process, const Address &addr)
+ // const;
+ //
+ bool ContainsAddress(lldb::addr_t func_load_addr, lldb::addr_t addr) const;
+
+ void SetModule(const lldb::ModuleSP &module) { m_module_wp = module; }
+
+ bool Evaluate(ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
+ lldb::addr_t func_load_addr, const Value *initial_value_ptr,
+ const Value *object_address_ptr, Value &result,
+ Status *error_ptr) const;
+
+private:
+ // RangeDataVector requires a comparator for DWARFExpression, but it doesn't
+ // make sense to do so.
+ struct DWARFExpressionCompare {
+ public:
+ bool operator()(const DWARFExpression &lhs,
+ const DWARFExpression &rhs) const {
+ return false;
+ }
+ };
+ using ExprVec = RangeDataVector<lldb::addr_t, lldb::addr_t, DWARFExpression,
+ 0, DWARFExpressionCompare>;
+ using Entry = ExprVec::Entry;
+
+ // File address range mapping to single dwarf expression.
+ ExprVec m_exprs;
+
+ /// Module which defined this expression.
+ lldb::ModuleWP m_module_wp;
+
+ /// The DWARF compile unit this expression belongs to. It is used to evaluate
+ /// values indexing into the .debug_addr section (e.g. DW_OP_GNU_addr_index,
+ /// DW_OP_GNU_const_index)
+ const DWARFUnit *m_dwarf_cu = nullptr;
+
+ // Function base file address.
+ lldb::addr_t m_func_file_addr = LLDB_INVALID_ADDRESS;
+
+ using const_iterator = ExprVec::Collection::const_iterator;
+ const_iterator begin() const { return m_exprs.begin(); }
+ const_iterator end() const { return m_exprs.end(); }
+};
+} // namespace lldb_private
+
+#endif // LLDB_EXPRESSION_DWARFEXPRESSIONLIST_H
diff --git a/lldb/include/lldb/Interpreter/CommandObject.h b/lldb/include/lldb/Interpreter/CommandObject.h
index 45fc47b02c04..0fc1c61bdb92 100644
--- a/lldb/include/lldb/Interpreter/CommandObject.h
+++ b/lldb/include/lldb/Interpreter/CommandObject.h
@@ -104,9 +104,6 @@ public:
typedef std::vector<CommandArgumentData>
CommandArgumentEntry; // Used to build individual command argument lists
- static ArgumentTableEntry g_arguments_data
- [lldb::eArgTypeLastArg]; // Main argument information table
-
typedef std::map<std::string, lldb::CommandObjectSP> CommandMap;
CommandObject(CommandInterpreter &interpreter, llvm::StringRef name,
diff --git a/lldb/include/lldb/Symbol/Function.h b/lldb/include/lldb/Symbol/Function.h
index 83f9979c3c52..3eb4f5d7dedf 100644
--- a/lldb/include/lldb/Symbol/Function.h
+++ b/lldb/include/lldb/Symbol/Function.h
@@ -12,7 +12,7 @@
#include "lldb/Core/AddressRange.h"
#include "lldb/Core/Declaration.h"
#include "lldb/Core/Mangled.h"
-#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Expression/DWARFExpressionList.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Utility/UserID.h"
#include "llvm/ADT/ArrayRef.h"
@@ -253,8 +253,8 @@ class Function;
/// Represent the locations of a parameter at a call site, both in the caller
/// and in the callee.
struct CallSiteParameter {
- DWARFExpression LocationInCallee;
- DWARFExpression LocationInCaller;
+ DWARFExpressionList LocationInCallee;
+ DWARFExpressionList LocationInCaller;
};
/// A vector of \c CallSiteParameter.
@@ -370,7 +370,7 @@ class IndirectCallEdge : public CallEdge {
public:
/// Construct a call edge using a DWARFExpression to identify the callee, and
/// a return PC within the calling function to identify a specific call site.
- IndirectCallEdge(DWARFExpression call_target, AddrType caller_address_type,
+ IndirectCallEdge(DWARFExpressionList call_target, AddrType caller_address_type,
lldb::addr_t caller_address, bool is_tail_call,
CallSiteParameterArray &&parameters)
: CallEdge(caller_address_type, caller_address, is_tail_call,
@@ -383,7 +383,7 @@ private:
// Used to describe an indirect call.
//
// Specifies the location of the callee address in the calling frame.
- DWARFExpression call_target;
+ DWARFExpressionList call_target;
};
/// \class Function Function.h "lldb/Symbol/Function.h"
@@ -521,13 +521,13 @@ public:
/// \return
/// A location expression that describes the function frame
/// base.
- DWARFExpression &GetFrameBaseExpression() { return m_frame_base; }
+ DWARFExpressionList &GetFrameBaseExpression() { return m_frame_base; }
/// Get const accessor for the frame base location.
///
/// \return
/// A const compile unit object pointer.
- const DWARFExpression &GetFrameBaseExpression() const { return m_frame_base; }
+ const DWARFExpressionList &GetFrameBaseExpression() const { return m_frame_base; }
ConstString GetName() const;
@@ -659,7 +659,7 @@ protected:
/// The frame base expression for variables that are relative to the frame
/// pointer.
- DWARFExpression m_frame_base;
+ DWARFExpressionList m_frame_base;
Flags m_flags;
diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h
index c61e3c138944..e51d50592c90 100644
--- a/lldb/include/lldb/Symbol/ObjectFile.h
+++ b/lldb/include/lldb/Symbol/ObjectFile.h
@@ -673,6 +673,7 @@ public:
virtual size_t ReadSectionData(Section *section,
DataExtractor &section_data);
+ /// Returns true if the object file exists only in memory.
bool IsInMemory() const { return m_memory_addr != LLDB_INVALID_ADDRESS; }
// Strip linker annotations (such as @@VERSION) from symbol names.
@@ -736,6 +737,7 @@ protected:
DataExtractor
m_data; ///< The data for this object file so things can be parsed lazily.
lldb::ProcessWP m_process_wp;
+ /// Set if the object file only exists in memory.
const lldb::addr_t m_memory_addr;
std::unique_ptr<lldb_private::SectionList> m_sections_up;
std::unique_ptr<lldb_private::Symtab> m_symtab_up;
diff --git a/lldb/include/lldb/Symbol/TypeList.h b/lldb/include/lldb/Symbol/TypeList.h
index 03390858025b..403469c989f5 100644
--- a/lldb/include/lldb/Symbol/TypeList.h
+++ b/lldb/include/lldb/Symbol/TypeList.h
@@ -49,10 +49,11 @@ public:
void ForEach(std::function<bool(lldb::TypeSP &type_sp)> const &callback);
- void RemoveMismatchedTypes(const char *qualified_typename, bool exact_match);
+ void RemoveMismatchedTypes(llvm::StringRef qualified_typename,
+ bool exact_match);
- void RemoveMismatchedTypes(const std::string &type_scope,
- const std::string &type_basename,
+ void RemoveMismatchedTypes(llvm::StringRef type_scope,
+ llvm::StringRef type_basename,
lldb::TypeClass type_class, bool exact_match);
void RemoveMismatchedTypes(lldb::TypeClass type_class);
diff --git a/lldb/include/lldb/Symbol/TypeMap.h b/lldb/include/lldb/Symbol/TypeMap.h
index ede54c1a09d4..c200ccb9844f 100644
--- a/lldb/include/lldb/Symbol/TypeMap.h
+++ b/lldb/include/lldb/Symbol/TypeMap.h
@@ -53,14 +53,10 @@ public:
bool Remove(const lldb::TypeSP &type_sp);
- void RemoveMismatchedTypes(const char *qualified_typename, bool exact_match);
-
- void RemoveMismatchedTypes(const std::string &type_scope,
- const std::string &type_basename,
+ void RemoveMismatchedTypes(llvm::StringRef type_scope,
+ llvm::StringRef type_basename,
lldb::TypeClass type_class, bool exact_match);
- void RemoveMismatchedTypes(lldb::TypeClass type_class);
-
private:
typedef collection::iterator iterator;
typedef collection::const_iterator const_iterator;
diff --git a/lldb/include/lldb/Symbol/Variable.h b/lldb/include/lldb/Symbol/Variable.h
index 88a975df3992..c437624d1ea6 100644
--- a/lldb/include/lldb/Symbol/Variable.h
+++ b/lldb/include/lldb/Symbol/Variable.h
@@ -11,7 +11,7 @@
#include "lldb/Core/Declaration.h"
#include "lldb/Core/Mangled.h"
-#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Expression/DWARFExpressionList.h"
#include "lldb/Utility/CompletionRequest.h"
#include "lldb/Utility/RangeMap.h"
#include "lldb/Utility/UserID.h"
@@ -32,8 +32,8 @@ public:
Variable(lldb::user_id_t uid, const char *name, const char *mangled,
const lldb::SymbolFileTypeSP &symfile_type_sp, lldb::ValueType scope,
SymbolContextScope *owner_scope, const RangeList &scope_range,
- Declaration *decl, const DWARFExpression &location, bool external,
- bool artificial, bool location_is_constant_data,
+ Declaration *decl, const DWARFExpressionList &location,
+ bool external, bool artificial, bool location_is_constant_data,
bool static_member = false);
virtual ~Variable();
@@ -73,9 +73,11 @@ public:
bool IsStaticMember() const { return m_static_member; }
- DWARFExpression &LocationExpression() { return m_location; }
+ DWARFExpressionList &LocationExpressionList() { return m_location_list; }
- const DWARFExpression &LocationExpression() const { return m_location; }
+ const DWARFExpressionList &LocationExpressionList() const {
+ return m_location_list;
+ }
// When given invalid address, it dumps all locations. Otherwise it only dumps
// the location that contains this address.
@@ -128,7 +130,7 @@ protected:
Declaration m_declaration;
/// The location of this variable that can be fed to
/// DWARFExpression::Evaluate().
- DWARFExpression m_location;
+ DWARFExpressionList m_location_list;
/// Visible outside the containing compile unit?
unsigned m_external : 1;
/// Non-zero if the variable is not explicitly declared in source.
diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h
index 1b0485b22cac..7c4340de4de0 100644
--- a/lldb/include/lldb/Target/StackFrame.h
+++ b/lldb/include/lldb/Target/StackFrame.h
@@ -202,7 +202,7 @@ public:
/// frames may be unable to provide this value; they will return false.
bool GetFrameBaseValue(Scalar &value, Status *error_ptr);
- /// Get the DWARFExpression corresponding to the Canonical Frame Address.
+ /// Get the DWARFExpressionList corresponding to the Canonical Frame Address.
///
/// Often a register (bp), but sometimes a register + offset.
///
@@ -212,7 +212,7 @@ public:
///
/// \return
/// Returns the corresponding DWARF expression, or NULL.
- DWARFExpression *GetFrameBaseExpression(Status *error_ptr);
+ DWARFExpressionList *GetFrameBaseExpression(Status *error_ptr);
/// Get the current lexical scope block for this StackFrame, if possible.
///
diff --git a/lldb/include/lldb/Target/Trace.h b/lldb/include/lldb/Target/Trace.h
index f4d7dee684c3..beae9e28417d 100644
--- a/lldb/include/lldb/Target/Trace.h
+++ b/lldb/include/lldb/Target/Trace.h
@@ -56,21 +56,24 @@ public:
/// A stream object to dump the information to.
virtual void Dump(Stream *s) const = 0;
- /// Save the trace of a live process to the specified directory, which
- /// will be created if needed.
- /// This will also create a a file \a <directory>/trace.json with the main
- /// properties of the trace session, along with others files which contain
- /// the actual trace data. The trace.json file can be used later as input
- /// for the "trace load" command to load the trace in LLDB.
- /// The process being trace is not a live process, return an error.
+ /// Save the trace to the specified directory, which will be created if
+ /// needed. This will also create a a file \a <directory>/trace.json with the
+ /// main properties of the trace session, along with others files which
+ /// contain the actual trace data. The trace.json file can be used later as
+ /// input for the "trace load" command to load the trace in LLDB.
///
/// \param[in] directory
/// The directory where the trace files will be saved.
///
+ /// \param[in] compact
+ /// Try not to save to disk information irrelevant to the traced processes.
+ /// Each trace plug-in implements this in a different fashion.
+ ///
/// \return
- /// \a llvm::success if the operation was successful, or an \a llvm::Error
- /// otherwise.
- virtual llvm::Error SaveLiveTraceToDisk(FileSpec directory) = 0;
+ /// A \a FileSpec pointing to the bundle description file, or an \a
+ /// llvm::Error otherwise.
+ virtual llvm::Expected<FileSpec> SaveToDisk(FileSpec directory,
+ bool compact) = 0;
/// Find a trace plug-in using JSON data.
///
@@ -183,7 +186,8 @@ public:
/// \param[in] verbose
/// If \b true, print detailed info
/// If \b false, print compact info
- virtual void DumpTraceInfo(Thread &thread, Stream &s, bool verbose) = 0;
+ virtual void DumpTraceInfo(Thread &thread, Stream &s, bool verbose,
+ bool json) = 0;
/// Check if a thread is currently traced by this object.
///
diff --git a/lldb/include/lldb/Target/TraceCursor.h b/lldb/include/lldb/Target/TraceCursor.h
index a4cf6433c19a..f6337e3d3d3f 100644
--- a/lldb/include/lldb/Target/TraceCursor.h
+++ b/lldb/include/lldb/Target/TraceCursor.h
@@ -266,6 +266,16 @@ public:
/// 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.
+ ///
+ /// \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;
/// \}
protected:
diff --git a/lldb/include/lldb/Target/TraceDumper.h b/lldb/include/lldb/Target/TraceDumper.h
index e78836e45b01..bbc1a55873d7 100644
--- a/lldb/include/lldb/Target/TraceDumper.h
+++ b/lldb/include/lldb/Target/TraceDumper.h
@@ -34,6 +34,8 @@ struct TraceDumperOptions {
bool show_tsc = false;
/// Dump the events that happened between instructions.
bool show_events = false;
+ /// For each instruction, print the instruction kind.
+ bool show_control_flow_kind = false;
/// Optional custom id to start traversing from.
llvm::Optional<uint64_t> id = llvm::None;
/// Optional number of instructions to skip from the starting position
@@ -64,6 +66,7 @@ public:
llvm::Optional<lldb::TraceEvent> event;
llvm::Optional<SymbolInfo> symbol_info;
llvm::Optional<SymbolInfo> prev_symbol_info;
+ llvm::Optional<lldb::cpu_id_t> cpu_id;
};
/// Interface used to abstract away the format in which the instruction
diff --git a/lldb/include/lldb/Utility/Environment.h b/lldb/include/lldb/Utility/Environment.h
index c1549a3d60a6..27d740402c30 100644
--- a/lldb/include/lldb/Utility/Environment.h
+++ b/lldb/include/lldb/Utility/Environment.h
@@ -57,7 +57,7 @@ public:
using Base::operator[];
Environment() {}
- Environment(const Environment &RHS) : Base(RHS) {}
+ Environment(const Environment &RHS) : Base(static_cast<const Base&>(RHS)) {}
Environment(Environment &&RHS) : Base(std::move(RHS)) {}
Environment(char *const *Env)
: Environment(const_cast<const char *const *>(Env)) {}
diff --git a/lldb/include/lldb/Utility/RangeMap.h b/lldb/include/lldb/Utility/RangeMap.h
index 7eb0cab8084c..257b177c7092 100644
--- a/lldb/include/lldb/Utility/RangeMap.h
+++ b/lldb/include/lldb/Utility/RangeMap.h
@@ -627,6 +627,10 @@ public:
return (m_entries.empty() ? nullptr : &m_entries.back());
}
+ using const_iterator = typename Collection::const_iterator;
+ const_iterator begin() const { return m_entries.begin(); }
+ const_iterator end() const { return m_entries.end(); }
+
protected:
Collection m_entries;
Compare m_compare;
diff --git a/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h b/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
index 36b594613a91..bf9409743a6d 100644
--- a/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
+++ b/lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
@@ -50,6 +50,10 @@ struct TraceIntelPTStartRequest : TraceStartRequest {
/// Whether to have a trace buffer per thread or per cpu cpu.
llvm::Optional<bool> per_cpu_tracing;
+ /// Disable the cgroup filtering that is automatically applied in per cpu
+ /// mode.
+ llvm::Optional<bool> disable_cgroup_filtering;
+
bool IsPerCpuTracing() const;
};
@@ -107,6 +111,7 @@ struct LinuxPerfZeroTscConversion {
struct TraceIntelPTGetStateResponse : TraceGetStateResponse {
/// The TSC to wall time conversion if it exists, otherwise \b nullptr.
llvm::Optional<LinuxPerfZeroTscConversion> tsc_perf_zero_conversion;
+ bool using_cgroup_filtering = false;
};
bool fromJSON(const llvm::json::Value &value,
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index eba2667727f2..ad03f7e43056 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -970,20 +970,30 @@ enum ExpressionEvaluationPhase {
/// control flow of a trace.
///
/// A single instruction can match one or more of these categories.
-FLAGS_ENUM(TraceInstructionControlFlowType){
- /// Any instruction.
- eTraceInstructionControlFlowTypeInstruction = (1u << 1),
- /// A conditional or unconditional branch/jump.
- eTraceInstructionControlFlowTypeBranch = (1u << 2),
- /// A conditional or unconditional branch/jump that changed
- /// the control flow of the program.
- eTraceInstructionControlFlowTypeTakenBranch = (1u << 3),
- /// A call to a function.
- eTraceInstructionControlFlowTypeCall = (1u << 4),
- /// A return from a function.
- eTraceInstructionControlFlowTypeReturn = (1u << 5)};
-
-LLDB_MARK_AS_BITMASK_ENUM(TraceInstructionControlFlowType)
+enum InstructionControlFlowKind {
+ /// The instruction could not be classified.
+ eInstructionControlFlowKindUnknown = 0,
+ /// The instruction is something not listed below, i.e. it's a sequential
+ /// instruction that doesn't affect the control flow of the program.
+ eInstructionControlFlowKindOther,
+ /// The instruction is a near (function) call.
+ eInstructionControlFlowKindCall,
+ /// The instruction is a near (function) return.
+ eInstructionControlFlowKindReturn,
+ /// The instruction is a near unconditional jump.
+ eInstructionControlFlowKindJump,
+ /// The instruction is a near conditional jump.
+ eInstructionControlFlowKindCondJump,
+ /// The instruction is a call-like far transfer.
+ /// E.g. SYSCALL, SYSENTER, or FAR CALL.
+ eInstructionControlFlowKindFarCall,
+ /// The instruction is a return-like far transfer.
+ /// E.g. SYSRET, SYSEXIT, IRET, or FAR RET.
+ eInstructionControlFlowKindFarReturn,
+ /// The instruction is a jump-like far transfer.
+ /// E.g. FAR JMP.
+ eInstructionControlFlowKindFarJump
+};
/// Watchpoint Kind.
///
@@ -1153,12 +1163,15 @@ enum TraceCounter {
eTraceCounterTSC = 0,
};
-// Events that might happen during a trace session.
+/// Events that might happen during a trace session.
enum TraceEvent {
- // Tracing was disabled for some time due to a software trigger
+ /// Tracing was disabled for some time due to a software trigger
eTraceEventDisabledSW,
- // Tracing was disable for some time due to a hardware trigger
+ /// Tracing was disable for some time due to a hardware trigger
eTraceEventDisabledHW,
+ /// 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,
};
// Enum used to identify which kind of item a \a TraceCursor is pointing at
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index 487b2f20792b..c51e1850338f 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -66,6 +66,7 @@ class ConstStringTable;
class DWARFCallFrameInfo;
class DWARFDataExtractor;
class DWARFExpression;
+class DWARFExpressionList;
class DataBuffer;
class WritableDataBuffer;
class DataBufferHeap;
diff --git a/lldb/source/API/SBInstruction.cpp b/lldb/source/API/SBInstruction.cpp
index 6cb9e5dbc1af..ced22628a297 100644
--- a/lldb/source/API/SBInstruction.cpp
+++ b/lldb/source/API/SBInstruction.cpp
@@ -241,7 +241,8 @@ bool SBInstruction::GetDescription(lldb::SBStream &s) {
// didn't have a stream already created, one will get created...
FormatEntity::Entry format;
FormatEntity::Parse("${addr}: ", format);
- inst_sp->Dump(&s.ref(), 0, true, false, nullptr, &sc, nullptr, &format, 0);
+ inst_sp->Dump(&s.ref(), 0, true, false, /*show_control_flow_kind=*/false,
+ nullptr, &sc, nullptr, &format, 0);
return true;
}
return false;
@@ -275,8 +276,8 @@ void SBInstruction::Print(FileSP out_sp) {
StreamFile out_stream(out_sp);
FormatEntity::Entry format;
FormatEntity::Parse("${addr}: ", format);
- inst_sp->Dump(&out_stream, 0, true, false, nullptr, &sc, nullptr, &format,
- 0);
+ inst_sp->Dump(&out_stream, 0, true, false, /*show_control_flow_kind=*/false,
+ nullptr, &sc, nullptr, &format, 0);
}
}
diff --git a/lldb/source/API/SBInstructionList.cpp b/lldb/source/API/SBInstructionList.cpp
index e289e8e9343d..ae87d7965766 100644
--- a/lldb/source/API/SBInstructionList.cpp
+++ b/lldb/source/API/SBInstructionList.cpp
@@ -165,8 +165,9 @@ bool SBInstructionList::GetDescription(Stream &sref) {
addr, eSymbolContextEverything, sc);
}
- inst->Dump(&sref, max_opcode_byte_size, true, false, nullptr, &sc,
- &prev_sc, &format, 0);
+ inst->Dump(&sref, max_opcode_byte_size, true, false,
+ /*show_control_flow_kind=*/false, nullptr, &sc, &prev_sc,
+ &format, 0);
sref.EOL();
}
return true;
diff --git a/lldb/source/API/SBSection.cpp b/lldb/source/API/SBSection.cpp
index 733e0db0b5ba..3a9cf20e484a 100644
--- a/lldb/source/API/SBSection.cpp
+++ b/lldb/source/API/SBSection.cpp
@@ -242,6 +242,15 @@ uint32_t SBSection::GetTargetByteSize() {
return 0;
}
+uint32_t SBSection::GetAlignment() {
+ LLDB_INSTRUMENT_VA(this);
+
+ SectionSP section_sp(GetSP());
+ if (section_sp.get())
+ return (1 << section_sp->GetLog2Align());
+ return 0;
+}
+
bool SBSection::operator==(const SBSection &rhs) {
LLDB_INSTRUMENT_VA(this, rhs);
diff --git a/lldb/source/API/SBTrace.cpp b/lldb/source/API/SBTrace.cpp
index fe9003237073..2b1f140161b6 100644
--- a/lldb/source/API/SBTrace.cpp
+++ b/lldb/source/API/SBTrace.cpp
@@ -43,6 +43,24 @@ SBTrace SBTrace::LoadTraceFromFile(SBError &error, SBDebugger &debugger,
return SBTrace(trace_or_err.get());
}
+SBFileSpec SBTrace::SaveToDisk(SBError &error, const SBFileSpec &bundle_dir,
+ bool compact) {
+ LLDB_INSTRUMENT_VA(this, error, bundle_dir, compact);
+
+ error.Clear();
+ SBFileSpec file_spec;
+
+ if (!m_opaque_sp)
+ error.SetErrorString("error: invalid trace");
+ else if (Expected<FileSpec> desc_file =
+ m_opaque_sp->SaveToDisk(bundle_dir.ref(), compact))
+ file_spec.SetFileSpec(*desc_file);
+ else
+ error.SetErrorString(llvm::toString(desc_file.takeError()).c_str());
+
+ return file_spec;
+}
+
const char *SBTrace::GetStartConfigurationHelp() {
LLDB_INSTRUMENT_VA(this);
return m_opaque_sp ? m_opaque_sp->GetStartConfigurationHelp() : nullptr;
diff --git a/lldb/source/Commands/CommandObjectDisassemble.cpp b/lldb/source/Commands/CommandObjectDisassemble.cpp
index 9d081c83c0fb..6c33edc8a3a8 100644
--- a/lldb/source/Commands/CommandObjectDisassemble.cpp
+++ b/lldb/source/Commands/CommandObjectDisassemble.cpp
@@ -65,6 +65,10 @@ Status CommandObjectDisassemble::CommandOptions::SetOptionValue(
show_bytes = true;
break;
+ case 'k':
+ show_control_flow_kind = true;
+ break;
+
case 's': {
start_addr = OptionArgParser::ToAddress(execution_context, option_arg,
LLDB_INVALID_ADDRESS, &error);
@@ -154,6 +158,7 @@ void CommandObjectDisassemble::CommandOptions::OptionParsingStarting(
ExecutionContext *execution_context) {
show_mixed = false;
show_bytes = false;
+ show_control_flow_kind = false;
num_lines_context = 0;
num_instructions = 0;
func_name.clear();
@@ -493,6 +498,9 @@ bool CommandObjectDisassemble::DoExecute(Args &command,
if (m_options.show_bytes)
options |= Disassembler::eOptionShowBytes;
+ if (m_options.show_control_flow_kind)
+ options |= Disassembler::eOptionShowControlFlowKind;
+
if (m_options.raw)
options |= Disassembler::eOptionRawOuput;
diff --git a/lldb/source/Commands/CommandObjectDisassemble.h b/lldb/source/Commands/CommandObjectDisassemble.h
index a4b3df8724da..b5146863628d 100644
--- a/lldb/source/Commands/CommandObjectDisassemble.h
+++ b/lldb/source/Commands/CommandObjectDisassemble.h
@@ -46,6 +46,7 @@ public:
bool show_mixed; // Show mixed source/assembly
bool show_bytes;
+ bool show_control_flow_kind;
uint32_t num_lines_context = 0;
uint32_t num_instructions = 0;
bool raw;
diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index c76ae99057f2..d36a574aba7d 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -579,14 +579,14 @@ protected:
}
}
}
-
+
Target *target = m_exe_ctx.GetTargetPtr();
BreakpointIDList run_to_bkpt_ids;
// Don't pass an empty run_to_breakpoint list, as Verify will look for the
// default breakpoint.
if (m_options.m_run_to_bkpt_args.GetArgumentCount() > 0)
CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
- m_options.m_run_to_bkpt_args, target, result, &run_to_bkpt_ids,
+ m_options.m_run_to_bkpt_args, target, result, &run_to_bkpt_ids,
BreakpointName::Permissions::disablePerm);
if (!result.Succeeded()) {
return false;
@@ -604,7 +604,7 @@ protected:
std::vector<break_id_t> bkpts_disabled;
std::vector<BreakpointID> locs_disabled;
if (num_run_to_bkpt_ids != 0) {
- // Go through the ID's specified, and separate the breakpoints from are
+ // Go through the ID's specified, and separate the breakpoints from are
// the breakpoint.location specifications since the latter require
// special handling. We also figure out whether there's at least one
// specifier in the set that is enabled.
@@ -613,22 +613,22 @@ protected:
std::unordered_set<break_id_t> bkpts_with_locs_seen;
BreakpointIDList with_locs;
bool any_enabled = false;
-
+
for (size_t idx = 0; idx < num_run_to_bkpt_ids; idx++) {
BreakpointID bkpt_id = run_to_bkpt_ids.GetBreakpointIDAtIndex(idx);
break_id_t bp_id = bkpt_id.GetBreakpointID();
break_id_t loc_id = bkpt_id.GetLocationID();
- BreakpointSP bp_sp
+ BreakpointSP bp_sp
= bkpt_list.FindBreakpointByID(bp_id);
- // Note, VerifyBreakpointOrLocationIDs checks for existence, so we
+ // Note, VerifyBreakpointOrLocationIDs checks for existence, so we
// don't need to do it again here.
if (bp_sp->IsEnabled()) {
if (loc_id == LLDB_INVALID_BREAK_ID) {
- // A breakpoint (without location) was specified. Make sure that
+ // A breakpoint (without location) was specified. Make sure that
// at least one of the locations is enabled.
size_t num_locations = bp_sp->GetNumLocations();
for (size_t loc_idx = 0; loc_idx < num_locations; loc_idx++) {
- BreakpointLocationSP loc_sp
+ BreakpointLocationSP loc_sp
= bp_sp->GetLocationAtIndex(loc_idx);
if (loc_sp->IsEnabled()) {
any_enabled = true;
@@ -641,7 +641,7 @@ protected:
if (loc_sp->IsEnabled())
any_enabled = true;
}
-
+
// Then sort the bp & bp.loc entries for later use:
if (bkpt_id.GetLocationID() == LLDB_INVALID_BREAK_ID)
bkpts_seen.insert(bkpt_id.GetBreakpointID());
@@ -653,14 +653,14 @@ protected:
}
// Do all the error checking here so once we start disabling we don't
// have to back out half-way through.
-
+
// Make sure at least one of the specified breakpoints is enabled.
if (!any_enabled) {
result.AppendError("at least one of the continue-to breakpoints must "
"be enabled.");
return false;
}
-
+
// Also, if you specify BOTH a breakpoint and one of it's locations,
// we flag that as an error, since it won't do what you expect, the
// breakpoint directive will mean "run to all locations", which is not
@@ -671,7 +671,7 @@ protected:
"one of its locations: {0}", bp_id);
}
}
-
+
// Now go through the breakpoints in the target, disabling all the ones
// that the user didn't mention:
for (BreakpointSP bp_sp : bkpt_list.Breakpoints()) {
@@ -695,7 +695,7 @@ protected:
BreakpointLocationSP loc_sp = bp_sp->GetLocationAtIndex(loc_idx);
tmp_id.SetBreakpointLocationID(loc_idx);
size_t position = 0;
- if (!with_locs.FindBreakpointID(tmp_id, &position)
+ if (!with_locs.FindBreakpointID(tmp_id, &position)
&& loc_sp->IsEnabled()) {
locs_disabled.push_back(tmp_id);
loc_sp->SetEnabled(false);
@@ -723,20 +723,20 @@ protected:
Status error;
// For now we can only do -b with synchronous:
bool old_sync = GetDebugger().GetAsyncExecution();
-
+
if (run_to_bkpt_ids.GetSize() != 0) {
GetDebugger().SetAsyncExecution(false);
synchronous_execution = true;
- }
+ }
if (synchronous_execution)
error = process->ResumeSynchronous(&stream);
else
error = process->Resume();
-
+
if (run_to_bkpt_ids.GetSize() != 0) {
GetDebugger().SetAsyncExecution(old_sync);
- }
-
+ }
+
// Now re-enable the breakpoints we disabled:
BreakpointList &bkpt_list = target->GetBreakpointList();
for (break_id_t bp_id : bkpts_disabled) {
@@ -745,10 +745,10 @@ protected:
bp_sp->SetEnabled(true);
}
for (const BreakpointID &bkpt_id : locs_disabled) {
- BreakpointSP bp_sp
+ BreakpointSP bp_sp
= bkpt_list.FindBreakpointByID(bkpt_id.GetBreakpointID());
if (bp_sp) {
- BreakpointLocationSP loc_sp
+ BreakpointLocationSP loc_sp
= bp_sp->FindLocationByID(bkpt_id.GetLocationID());
if (loc_sp)
loc_sp->SetEnabled(true);
@@ -1731,7 +1731,7 @@ protected:
bool DoExecute(Args &signal_args, CommandReturnObject &result) override {
Target &target = GetSelectedOrDummyTarget();
- // Any signals that are being set should be added to the Target's
+ // Any signals that are being set should be added to the Target's
// DummySignals so they will get applied on rerun, etc.
// If we have a process, however, we can do a more accurate job of vetting
// the user's options.
@@ -1761,8 +1761,8 @@ protected:
"true or false.\n");
return false;
}
-
- bool no_actions = (stop_action == -1 && pass_action == -1
+
+ bool no_actions = (stop_action == -1 && pass_action == -1
&& notify_action == -1);
if (m_options.only_target_values && !no_actions) {
result.AppendError("-t is for reporting, not setting, target values.");
@@ -1832,9 +1832,9 @@ protected:
}
auto set_lazy_bool = [] (int action) -> LazyBool {
LazyBool lazy;
- if (action == -1)
+ if (action == -1)
lazy = eLazyBoolCalculate;
- else if (action)
+ else if (action)
lazy = eLazyBoolYes;
else
lazy = eLazyBoolNo;
@@ -1876,7 +1876,7 @@ protected:
PrintSignalInformation(result.GetOutputStream(), signal_args,
num_signals_set, signals_sp);
else
- target.PrintDummySignals(result.GetOutputStream(),
+ target.PrintDummySignals(result.GetOutputStream(),
signal_args);
if (num_signals_set > 0)
@@ -1909,80 +1909,6 @@ protected:
}
};
-// CommandObjectProcessTraceSave
-#define LLDB_OPTIONS_process_trace_save
-#include "CommandOptions.inc"
-
-#pragma mark CommandObjectProcessTraceSave
-
-class CommandObjectProcessTraceSave : public CommandObjectParsed {
-public:
- class CommandOptions : public Options {
- public:
- CommandOptions() { OptionParsingStarting(nullptr); }
-
- Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
- ExecutionContext *execution_context) override {
- Status error;
- const int short_option = m_getopt_table[option_idx].val;
-
- switch (short_option) {
-
- case 'd': {
- m_directory.SetFile(option_arg, FileSpec::Style::native);
- FileSystem::Instance().Resolve(m_directory);
- break;
- }
- default:
- llvm_unreachable("Unimplemented option");
- }
- return error;
- }
-
- void OptionParsingStarting(ExecutionContext *execution_context) override{};
-
- llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
- return llvm::makeArrayRef(g_process_trace_save_options);
- };
-
- FileSpec m_directory;
- };
-
- Options *GetOptions() override { return &m_options; }
- CommandObjectProcessTraceSave(CommandInterpreter &interpreter)
- : CommandObjectParsed(
- interpreter, "process trace save",
- "Save the trace of the current process in the specified directory. "
- "The directory will be created if needed. "
- "This will also create a file <directory>/trace.json with the main "
- "properties of the trace session, along with others files which "
- "contain the actual trace data. The trace.json file can be used "
- "later as input for the \"trace load\" command to load the trace "
- "in LLDB",
- "process trace save [<cmd-options>]",
- eCommandRequiresProcess | eCommandTryTargetAPILock |
- eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
- eCommandProcessMustBeTraced) {}
-
- ~CommandObjectProcessTraceSave() override = default;
-
-protected:
- bool DoExecute(Args &command, CommandReturnObject &result) override {
- ProcessSP process_sp = m_exe_ctx.GetProcessSP();
-
- TraceSP trace_sp = process_sp->GetTarget().GetTrace();
-
- if (llvm::Error err = trace_sp->SaveLiveTraceToDisk(m_options.m_directory))
- result.AppendError(toString(std::move(err)));
- else
- result.SetStatus(eReturnStatusSuccessFinishResult);
-
- return result.Succeeded();
- }
-
- CommandOptions m_options;
-};
-
// CommandObjectProcessTraceStop
class CommandObjectProcessTraceStop : public CommandObjectParsed {
public:
@@ -2020,8 +1946,6 @@ public:
: CommandObjectMultiword(
interpreter, "trace", "Commands for tracing the current process.",
"process trace <subcommand> [<subcommand objects>]") {
- LoadSubCommand("save", CommandObjectSP(
- new CommandObjectProcessTraceSave(interpreter)));
LoadSubCommand("start", CommandObjectSP(new CommandObjectProcessTraceStart(
interpreter)));
LoadSubCommand("stop", CommandObjectSP(
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 2b71f1bc7bc8..51978878c8b9 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -47,12 +47,18 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadSpec.h"
#include "lldb/Utility/Args.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/Timer.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-private-enumerations.h"
+#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/CompilerInvocation.h"
+#include "clang/Frontend/FrontendActions.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/FormatAdapters.h"
@@ -2155,6 +2161,59 @@ protected:
}
};
+class CommandObjectTargetModulesDumpClangPCMInfo : public CommandObjectParsed {
+public:
+ CommandObjectTargetModulesDumpClangPCMInfo(CommandInterpreter &interpreter)
+ : CommandObjectParsed(
+ interpreter, "target modules dump pcm-info",
+ "Dump information about the given clang module (pcm).") {
+ // Take a single file argument.
+ CommandArgumentData arg{eArgTypeFilename, eArgRepeatPlain};
+ m_arguments.push_back({arg});
+ }
+
+ ~CommandObjectTargetModulesDumpClangPCMInfo() override = default;
+
+protected:
+ bool DoExecute(Args &command, CommandReturnObject &result) override {
+ if (command.GetArgumentCount() != 1) {
+ result.AppendErrorWithFormat("'%s' takes exactly one pcm path argument.",
+ m_cmd_name.c_str());
+ return false;
+ }
+
+ const char *pcm_path = command.GetArgumentAtIndex(0);
+ FileSpec pcm_file{pcm_path};
+
+ if (pcm_file.GetFileNameExtension().GetStringRef() != ".pcm") {
+ result.AppendError("file must have a .pcm extension");
+ return false;
+ }
+
+ if (!FileSystem::Instance().Exists(pcm_file)) {
+ result.AppendError("pcm file does not exist");
+ return false;
+ }
+
+ clang::CompilerInstance compiler;
+ compiler.createDiagnostics();
+
+ const char *clang_args[] = {"clang", pcm_path};
+ compiler.setInvocation(clang::createInvocation(clang_args));
+
+ clang::DumpModuleInfoAction dump_module_info;
+ dump_module_info.OutputStream = &result.GetOutputStream().AsRawOstream();
+ // DumpModuleInfoAction requires ObjectFilePCHContainerReader.
+ compiler.getPCHContainerOperations()->registerReader(
+ std::make_unique<clang::ObjectFilePCHContainerReader>());
+
+ if (compiler.ExecuteAction(dump_module_info))
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+
+ return result.Succeeded();
+ }
+};
+
#pragma mark CommandObjectTargetModulesDumpClangAST
// Clang AST dumping command
@@ -2406,10 +2465,10 @@ public:
CommandObjectTargetModulesDump(CommandInterpreter &interpreter)
: CommandObjectMultiword(
interpreter, "target modules dump",
- "Commands for dumping information about one or "
- "more target modules.",
+ "Commands for dumping information about one or more target "
+ "modules.",
"target modules dump "
- "[headers|symtab|sections|ast|symfile|line-table] "
+ "[objfile|symtab|sections|ast|symfile|line-table|pcm-info] "
"[<file1> <file2> ...]") {
LoadSubCommand("objfile",
CommandObjectSP(
@@ -2429,6 +2488,10 @@ public:
LoadSubCommand("line-table",
CommandObjectSP(new CommandObjectTargetModulesDumpLineTable(
interpreter)));
+ LoadSubCommand(
+ "pcm-info",
+ CommandObjectSP(
+ new CommandObjectTargetModulesDumpClangPCMInfo(interpreter)));
}
~CommandObjectTargetModulesDump() override = default;
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index 993523e06736..ad49d27bb9a7 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -1033,11 +1033,21 @@ protected:
line_table->FindLineEntryByAddress(fun_end_addr, function_start,
&end_ptr);
+ // Since not all source lines will contribute code, check if we are
+ // setting the breakpoint on the exact line number or the nearest
+ // subsequent line number and set breakpoints at all the line table
+ // entries of the chosen line number (exact or nearest subsequent).
for (uint32_t line_number : line_numbers) {
+ LineEntry line_entry;
+ bool exact = false;
uint32_t start_idx_ptr = index_ptr;
+ start_idx_ptr = sc.comp_unit->FindLineEntry(
+ index_ptr, line_number, nullptr, exact, &line_entry);
+ if (start_idx_ptr != UINT32_MAX)
+ line_number = line_entry.line;
+ exact = true;
+ start_idx_ptr = index_ptr;
while (start_idx_ptr <= end_ptr) {
- LineEntry line_entry;
- const bool exact = false;
start_idx_ptr = sc.comp_unit->FindLineEntry(
start_idx_ptr, line_number, nullptr, exact, &line_entry);
if (start_idx_ptr == UINT32_MAX)
@@ -2164,6 +2174,10 @@ public:
m_dumper_options.forwards = true;
break;
}
+ case 'k': {
+ m_dumper_options.show_control_flow_kind = true;
+ break;
+ }
case 't': {
m_dumper_options.show_tsc = true;
break;
@@ -2337,6 +2351,10 @@ public:
m_verbose = true;
break;
}
+ case 'j': {
+ m_json = true;
+ break;
+ }
default:
llvm_unreachable("Unimplemented option");
}
@@ -2345,6 +2363,7 @@ public:
void OptionParsingStarting(ExecutionContext *execution_context) override {
m_verbose = false;
+ m_json = false;
}
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
@@ -2353,15 +2372,9 @@ public:
// Instance variables to hold the values for command options.
bool m_verbose;
+ bool m_json;
};
- bool DoExecute(Args &command, CommandReturnObject &result) override {
- Target &target = m_exe_ctx.GetTargetRef();
- result.GetOutputStream().Format("Trace technology: {0}\n",
- target.GetTrace()->GetPluginName());
- return CommandObjectIterateOverThreads::DoExecute(command, result);
- }
-
CommandObjectTraceDumpInfo(CommandInterpreter &interpreter)
: CommandObjectIterateOverThreads(
interpreter, "thread trace dump info",
@@ -2383,7 +2396,7 @@ protected:
ThreadSP thread_sp =
m_exe_ctx.GetProcessPtr()->GetThreadList().FindThreadByID(tid);
trace_sp->DumpTraceInfo(*thread_sp, result.GetOutputStream(),
- m_options.m_verbose);
+ m_options.m_verbose, m_options.m_json);
return true;
}
diff --git a/lldb/source/Commands/CommandObjectTrace.cpp b/lldb/source/Commands/CommandObjectTrace.cpp
index 17aded9ed2a0..227de2de7065 100644
--- a/lldb/source/Commands/CommandObjectTrace.cpp
+++ b/lldb/source/Commands/CommandObjectTrace.cpp
@@ -30,6 +30,108 @@ using namespace lldb;
using namespace lldb_private;
using namespace llvm;
+// CommandObjectTraceSave
+#define LLDB_OPTIONS_trace_save
+#include "CommandOptions.inc"
+
+#pragma mark CommandObjectTraceSave
+
+class CommandObjectTraceSave : public CommandObjectParsed {
+public:
+ class CommandOptions : public Options {
+ public:
+ CommandOptions() { OptionParsingStarting(nullptr); }
+
+ Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
+ ExecutionContext *execution_context) override {
+ Status error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option) {
+ case 'c': {
+ m_compact = true;
+ break;
+ }
+ default:
+ llvm_unreachable("Unimplemented option");
+ }
+ return error;
+ }
+
+ void OptionParsingStarting(ExecutionContext *execution_context) override {
+ m_compact = false;
+ };
+
+ llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
+ return llvm::makeArrayRef(g_trace_save_options);
+ };
+
+ bool m_compact;
+ };
+
+ Options *GetOptions() override { return &m_options; }
+
+ CommandObjectTraceSave(CommandInterpreter &interpreter)
+ : CommandObjectParsed(
+ interpreter, "trace save",
+ "Save the trace of the current target in the specified directory, "
+ "which will be created if needed. "
+ "This directory will contain a trace bundle, with all the "
+ "necessary files the reconstruct the trace session even on a "
+ "different computer. "
+ "Part of this bundle is the bundle description file with the name "
+ "trace.json. This file can be used by the \"trace load\" command "
+ "to load this trace in LLDB."
+ "Note: if the current target contains information of multiple "
+ "processes or targets, they all will be included in the bundle.",
+ "trace save [<cmd-options>] <bundle_directory>",
+ eCommandRequiresProcess | eCommandTryTargetAPILock |
+ eCommandProcessMustBeLaunched | eCommandProcessMustBePaused |
+ eCommandProcessMustBeTraced) {
+ CommandArgumentData bundle_dir{eArgTypeDirectoryName, eArgRepeatPlain};
+ m_arguments.push_back({bundle_dir});
+ }
+
+ void
+ HandleArgumentCompletion(CompletionRequest &request,
+ OptionElementVector &opt_element_vector) override {
+ CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
+ request, nullptr);
+ }
+
+ ~CommandObjectTraceSave() override = default;
+
+protected:
+ bool DoExecute(Args &command, CommandReturnObject &result) override {
+ if (command.size() != 1) {
+ result.AppendError("a single path to a directory where the trace bundle "
+ "will be created is required");
+ return false;
+ }
+
+ FileSpec bundle_dir(command[0].ref());
+ FileSystem::Instance().Resolve(bundle_dir);
+
+ ProcessSP process_sp = m_exe_ctx.GetProcessSP();
+
+ TraceSP trace_sp = process_sp->GetTarget().GetTrace();
+
+ if (llvm::Expected<FileSpec> desc_file =
+ trace_sp->SaveToDisk(bundle_dir, m_options.m_compact)) {
+ result.AppendMessageWithFormatv(
+ "Trace bundle description file written to: {0}", *desc_file);
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ } else {
+ result.AppendError(toString(desc_file.takeError()));
+ }
+
+ return result.Succeeded();
+ }
+
+ CommandOptions m_options;
+};
+
// CommandObjectTraceLoad
#define LLDB_OPTIONS_trace_load
#include "CommandOptions.inc"
@@ -75,11 +177,19 @@ public:
: CommandObjectParsed(
interpreter, "trace load",
"Load a post-mortem processor trace session from a trace bundle.",
- "trace load") {
- CommandArgumentData session_file_arg{eArgTypePath, eArgRepeatPlain};
+ "trace load <trace_description_file>") {
+ CommandArgumentData session_file_arg{eArgTypeFilename, eArgRepeatPlain};
m_arguments.push_back({session_file_arg});
}
+ void
+ HandleArgumentCompletion(CompletionRequest &request,
+ OptionElementVector &opt_element_vector) override {
+ CommandCompletions::InvokeCommonCompletionCallbacks(
+ GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
+ request, nullptr);
+ }
+
~CommandObjectTraceLoad() override = default;
Options *GetOptions() override { return &m_options; }
@@ -284,6 +394,8 @@ CommandObjectTrace::CommandObjectTrace(CommandInterpreter &interpreter)
CommandObjectSP(new CommandObjectTraceLoad(interpreter)));
LoadSubCommand("dump",
CommandObjectSP(new CommandObjectTraceDump(interpreter)));
+ LoadSubCommand("save",
+ CommandObjectSP(new CommandObjectTraceSave(interpreter)));
LoadSubCommand("schema",
CommandObjectSP(new CommandObjectTraceSchema(interpreter)));
}
diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td
index 7755daa878be..7981917fd8b5 100644
--- a/lldb/source/Commands/Options.td
+++ b/lldb/source/Commands/Options.td
@@ -300,6 +300,11 @@ let Command = "breakpoint command delete" in {
let Command = "disassemble" in {
def disassemble_options_bytes : Option<"bytes", "b">,
Desc<"Show opcode bytes when disassembling.">;
+ def disassemble_options_kind : Option<"kind", "k">,
+ 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 disassemble_options_context : Option<"context", "C">, Arg<"NumLines">,
Desc<"Number of context lines of source to show.">;
def disassemble_options_mixed : Option<"mixed", "m">,
@@ -783,14 +788,6 @@ let Command = "process save_core" in {
"This allows core files to be saved in different formats.">;
}
-let Command = "process trace save" in {
- def process_trace_save_directory: Option<"directory", "d">,
- Group<1>,
- Arg<"Value">, Required,
- Desc<"The directory where the trace will be saved."
- "It will be created if it does not exist.">;
-}
-
let Command = "script import" in {
def script_import_allow_reload : Option<"allow-reload", "r">, Group<1>,
Desc<"Allow the script to be loaded even if it was already loaded before. "
@@ -1150,6 +1147,11 @@ let Command = "thread trace dump instructions" in {
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.">;
+ 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.">;
@@ -1167,6 +1169,8 @@ let Command = "thread trace dump instructions" in {
let Command = "thread trace dump info" in {
def thread_trace_dump_info_verbose : Option<"verbose", "v">, Group<1>,
Desc<"show verbose thread trace dump info">;
+ def thread_trace_dump_info_json: Option<"json", "j">, Group<1>,
+ Desc<"Dump in JSON format.">;
}
let Command = "type summary add" in {
@@ -1349,6 +1353,14 @@ let Command = "trace load" in {
"implementation.">;
}
+let Command = "trace save" in {
+ def trace_save_compact: Option<"compact", "c">,
+ Group<1>,
+ Desc<"Try not to save to disk information irrelevant to the traced "
+ "processes. Each trace plug-in implements this in a different "
+ "fashion.">;
+}
+
let Command = "trace dump" in {
def trace_dump_verbose : Option<"verbose", "v">, Group<1>,
Desc<"Show verbose trace information.">;
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index f17cd8856a6d..62857c181af8 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -1835,9 +1835,20 @@ void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) {
// going to show the progress.
const uint64_t id = data->GetID();
if (m_current_event_id) {
+ Log *log = GetLog(LLDBLog::Events);
+ if (log && log->GetVerbose()) {
+ StreamString log_stream;
+ log_stream.AsRawOstream()
+ << static_cast<void *>(this) << " Debugger(" << GetID()
+ << ")::HandleProgressEvent( m_current_event_id = "
+ << *m_current_event_id << ", data = { ";
+ data->Dump(&log_stream);
+ log_stream << " } )";
+ log->PutString(log_stream.GetString());
+ }
if (id != *m_current_event_id)
return;
- if (data->GetCompleted())
+ if (data->GetCompleted() == data->GetTotal())
m_current_event_id.reset();
} else {
m_current_event_id = id;
@@ -1860,7 +1871,7 @@ void Debugger::HandleProgressEvent(const lldb::EventSP &event_sp) {
// Print over previous line, if any.
output->Printf("\r");
- if (data->GetCompleted()) {
+ if (data->GetCompleted() == data->GetTotal()) {
// Clear the current line.
output->Printf("\x1B[2K");
output->Flush();
diff --git a/lldb/source/Core/Disassembler.cpp b/lldb/source/Core/Disassembler.cpp
index 00d92053bc4f..7a9e214748a7 100644
--- a/lldb/source/Core/Disassembler.cpp
+++ b/lldb/source/Core/Disassembler.cpp
@@ -527,8 +527,11 @@ void Disassembler::PrintInstructions(Debugger &debugger, const ArchSpec &arch,
}
const bool show_bytes = (options & eOptionShowBytes) != 0;
- inst->Dump(&strm, max_opcode_byte_size, true, show_bytes, &exe_ctx, &sc,
- &prev_sc, nullptr, address_text_size);
+ const bool show_control_flow_kind =
+ (options & eOptionShowControlFlowKind) != 0;
+ inst->Dump(&strm, max_opcode_byte_size, true, show_bytes,
+ show_control_flow_kind, &exe_ctx, &sc, &prev_sc, nullptr,
+ address_text_size);
strm.EOL();
} else {
break;
@@ -568,6 +571,334 @@ 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();
@@ -576,6 +907,7 @@ AddressClass Instruction::GetAddressClass() {
void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size,
bool show_address, bool show_bytes,
+ bool show_control_flow_kind,
const ExecutionContext *exe_ctx,
const SymbolContext *sym_ctx,
const SymbolContext *prev_sym_ctx,
@@ -613,6 +945,38 @@ 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;
+ }
+ }
+
const size_t opcode_pos = ss.GetSizeOfLastLine();
// The default opcode size of 7 characters is plenty for most architectures
@@ -957,6 +1321,7 @@ InstructionSP InstructionList::GetInstructionAtAddress(const Address &address) {
}
void InstructionList::Dump(Stream *s, bool show_address, bool show_bytes,
+ bool show_control_flow_kind,
const ExecutionContext *exe_ctx) {
const uint32_t max_opcode_byte_size = GetMaxOpcocdeByteSize();
collection::const_iterator pos, begin, end;
@@ -975,8 +1340,9 @@ void InstructionList::Dump(Stream *s, bool show_address, bool show_bytes,
pos != end; ++pos) {
if (pos != begin)
s->EOL();
- (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes, exe_ctx,
- nullptr, nullptr, disassembly_format, 0);
+ (*pos)->Dump(s, max_opcode_byte_size, show_address, show_bytes,
+ show_control_flow_kind, exe_ctx, nullptr, nullptr,
+ disassembly_format, 0);
}
}
@@ -994,7 +1360,7 @@ InstructionList::GetIndexOfNextBranchInstruction(uint32_t start,
size_t num_instructions = m_instructions.size();
uint32_t next_branch = UINT32_MAX;
-
+
if (found_calls)
*found_calls = false;
for (size_t i = start; i < num_instructions; i++) {
diff --git a/lldb/source/Core/DumpDataExtractor.cpp b/lldb/source/Core/DumpDataExtractor.cpp
index 4ef1df1aeb0f..dc96a3454b72 100644
--- a/lldb/source/Core/DumpDataExtractor.cpp
+++ b/lldb/source/Core/DumpDataExtractor.cpp
@@ -170,10 +170,11 @@ static lldb::offset_t DumpInstructions(const DataExtractor &DE, Stream *s,
offset += bytes_consumed;
const bool show_address = base_addr != LLDB_INVALID_ADDRESS;
const bool show_bytes = true;
+ const bool show_control_flow_kind = true;
ExecutionContext exe_ctx;
exe_scope->CalculateExecutionContext(exe_ctx);
- disassembler_sp->GetInstructionList().Dump(s, show_address, show_bytes,
- &exe_ctx);
+ disassembler_sp->GetInstructionList().Dump(
+ s, show_address, show_bytes, show_control_flow_kind, &exe_ctx);
}
}
} else
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 41c21e1dc326..893e20837124 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -144,9 +144,7 @@ Module::Module(const ModuleSpec &module_spec)
module_spec.GetArchitecture().GetArchitectureName(),
module_spec.GetFileSpec().GetPath().c_str(),
module_spec.GetObjectName().IsEmpty() ? "" : "(",
- module_spec.GetObjectName().IsEmpty()
- ? ""
- : module_spec.GetObjectName().AsCString(""),
+ module_spec.GetObjectName().AsCString(""),
module_spec.GetObjectName().IsEmpty() ? "" : ")");
auto data_sp = module_spec.GetData();
@@ -254,8 +252,7 @@ Module::Module(const FileSpec &file_spec, const ArchSpec &arch,
LLDB_LOGF(log, "%p Module::Module((%s) '%s%s%s%s')",
static_cast<void *>(this), m_arch.GetArchitectureName(),
m_file.GetPath().c_str(), m_object_name.IsEmpty() ? "" : "(",
- m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
- m_object_name.IsEmpty() ? "" : ")");
+ m_object_name.AsCString(""), m_object_name.IsEmpty() ? "" : ")");
}
Module::Module() : m_file_has_changed(false), m_first_file_changed_log(false) {
@@ -283,8 +280,7 @@ Module::~Module() {
LLDB_LOGF(log, "%p Module::~Module((%s) '%s%s%s%s')",
static_cast<void *>(this), m_arch.GetArchitectureName(),
m_file.GetPath().c_str(), m_object_name.IsEmpty() ? "" : "(",
- m_object_name.IsEmpty() ? "" : m_object_name.AsCString(""),
- m_object_name.IsEmpty() ? "" : ")");
+ m_object_name.AsCString(""), m_object_name.IsEmpty() ? "" : ")");
// Release any auto pointers before we start tearing down our member
// variables since the object file and symbol files might need to make
// function calls back into this module object. The ordering is important
@@ -1000,8 +996,7 @@ void Module::FindTypes(
FindTypes_Impl(type_basename_const_str, CompilerDeclContext(), max_matches,
searched_symbol_files, typesmap);
if (typesmap.GetSize())
- typesmap.RemoveMismatchedTypes(std::string(type_scope),
- std::string(type_basename), type_class,
+ typesmap.RemoveMismatchedTypes(type_scope, type_basename, type_class,
exact_match);
} else {
// The type is not in a namespace/class scope, just search for it by
@@ -1011,15 +1006,13 @@ void Module::FindTypes(
// class prefix (like "struct", "class", "union", "typedef" etc).
FindTypes_Impl(ConstString(type_basename), CompilerDeclContext(),
UINT_MAX, searched_symbol_files, typesmap);
- typesmap.RemoveMismatchedTypes(std::string(type_scope),
- std::string(type_basename), type_class,
+ typesmap.RemoveMismatchedTypes(type_scope, type_basename, type_class,
exact_match);
} else {
FindTypes_Impl(name, CompilerDeclContext(), UINT_MAX,
searched_symbol_files, typesmap);
if (exact_match) {
- std::string name_str(name.AsCString(""));
- typesmap.RemoveMismatchedTypes(std::string(type_scope), name_str,
+ typesmap.RemoveMismatchedTypes(type_scope, name.GetStringRef(),
type_class, exact_match);
}
}
diff --git a/lldb/source/Core/ValueObjectVariable.cpp b/lldb/source/Core/ValueObjectVariable.cpp
index 8e89503a8a76..4e2bd12c1053 100644
--- a/lldb/source/Core/ValueObjectVariable.cpp
+++ b/lldb/source/Core/ValueObjectVariable.cpp
@@ -13,7 +13,7 @@
#include "lldb/Core/Declaration.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Value.h"
-#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Expression/DWARFExpressionList.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
@@ -127,17 +127,16 @@ bool ValueObjectVariable::UpdateValue() {
m_error.Clear();
Variable *variable = m_variable_sp.get();
- DWARFExpression &expr = variable->LocationExpression();
+ DWARFExpressionList &expr_list = variable->LocationExpressionList();
if (variable->GetLocationIsConstantValueData()) {
// expr doesn't contain DWARF bytes, it contains the constant variable
// value bytes themselves...
- if (expr.GetExpressionData(m_data)) {
- if (m_data.GetDataStart() && m_data.GetByteSize())
+ if (expr_list.GetExpressionData(m_data)) {
+ if (m_data.GetDataStart() && m_data.GetByteSize())
m_value.SetBytes(m_data.GetDataStart(), m_data.GetByteSize());
m_value.SetContext(Value::ContextType::Variable, variable);
- }
- else
+ } else
m_error.SetErrorString("empty constant data");
// constant bytes can't be edited - sorry
m_resolved_value.SetContext(Value::ContextType::Invalid, nullptr);
@@ -151,7 +150,7 @@ bool ValueObjectVariable::UpdateValue() {
m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
}
- if (expr.IsLocationList()) {
+ if (!expr_list.IsAlwaysValidSingleExpr()) {
SymbolContext sc;
variable->CalculateSymbolContext(&sc);
if (sc.function)
@@ -160,8 +159,8 @@ bool ValueObjectVariable::UpdateValue() {
target);
}
Value old_value(m_value);
- if (expr.Evaluate(&exe_ctx, nullptr, loclist_base_load_addr, nullptr,
- nullptr, m_value, &m_error)) {
+ if (expr_list.Evaluate(&exe_ctx, nullptr, loclist_base_load_addr, nullptr,
+ nullptr, m_value, &m_error)) {
m_resolved_value = m_value;
m_value.SetContext(Value::ContextType::Variable, variable);
@@ -246,7 +245,7 @@ bool ValueObjectVariable::UpdateValue() {
m_resolved_value.SetContext(Value::ContextType::Invalid, nullptr);
}
}
-
+
return m_error.Success();
}
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index 1f11907dc64c..9e6b21fc25ea 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -45,29 +45,10 @@ using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::dwarf;
-static lldb::addr_t
-ReadAddressFromDebugAddrSection(const DWARFUnit *dwarf_cu,
- uint32_t index) {
- uint32_t index_size = dwarf_cu->GetAddressByteSize();
- dw_offset_t addr_base = dwarf_cu->GetAddrBase();
- lldb::offset_t offset = addr_base + index * index_size;
- const DWARFDataExtractor &data =
- dwarf_cu->GetSymbolFileDWARF().GetDWARFContext().getOrLoadAddrData();
- if (data.ValidOffsetForDataOfSize(offset, index_size))
- return data.GetMaxU64_unchecked(&offset, index_size);
- return LLDB_INVALID_ADDRESS;
-}
-
// DWARFExpression constructor
-DWARFExpression::DWARFExpression() : m_module_wp(), m_data() {}
-
-DWARFExpression::DWARFExpression(lldb::ModuleSP module_sp,
- const DataExtractor &data,
- const DWARFUnit *dwarf_cu)
- : m_module_wp(), m_data(data), m_dwarf_cu(dwarf_cu) {
- if (module_sp)
- m_module_wp = module_sp;
-}
+DWARFExpression::DWARFExpression() : m_data() {}
+
+DWARFExpression::DWARFExpression(const DataExtractor &data) : m_data(data) {}
// Destructor
DWARFExpression::~DWARFExpression() = default;
@@ -86,71 +67,19 @@ void DWARFExpression::UpdateValue(uint64_t const_value,
m_data.SetAddressByteSize(addr_byte_size);
}
-void DWARFExpression::DumpLocation(Stream *s, const DataExtractor &data,
- lldb::DescriptionLevel level,
+void DWARFExpression::DumpLocation(Stream *s, lldb::DescriptionLevel level,
ABI *abi) const {
- llvm::DWARFExpression(data.GetAsLLVM(), data.GetAddressByteSize())
+ llvm::DWARFExpression(m_data.GetAsLLVM(), m_data.GetAddressByteSize())
.print(s->AsRawOstream(), llvm::DIDumpOptions(),
abi ? &abi->GetMCRegisterInfo() : nullptr, nullptr);
}
-void DWARFExpression::SetLocationListAddresses(addr_t cu_file_addr,
- addr_t func_file_addr) {
- m_loclist_addresses = LoclistAddresses{cu_file_addr, func_file_addr};
-}
-
-int DWARFExpression::GetRegisterKind() { return m_reg_kind; }
+RegisterKind DWARFExpression::GetRegisterKind() const { return m_reg_kind; }
void DWARFExpression::SetRegisterKind(RegisterKind reg_kind) {
m_reg_kind = reg_kind;
}
-bool DWARFExpression::IsLocationList() const {
- return bool(m_loclist_addresses);
-}
-
-namespace {
-/// Implement enough of the DWARFObject interface in order to be able to call
-/// DWARFLocationTable::dumpLocationList. We don't have access to a real
-/// DWARFObject here because DWARFExpression is used in non-DWARF scenarios too.
-class DummyDWARFObject final: public llvm::DWARFObject {
-public:
- DummyDWARFObject(bool IsLittleEndian) : IsLittleEndian(IsLittleEndian) {}
-
- bool isLittleEndian() const override { return IsLittleEndian; }
-
- llvm::Optional<llvm::RelocAddrEntry> find(const llvm::DWARFSection &Sec,
- uint64_t Pos) const override {
- return llvm::None;
- }
-private:
- bool IsLittleEndian;
-};
-}
-
-void DWARFExpression::GetDescription(Stream *s, lldb::DescriptionLevel level,
- ABI *abi) const {
- if (IsLocationList()) {
- // We have a location list
- lldb::offset_t offset = 0;
- std::unique_ptr<llvm::DWARFLocationTable> loctable_up =
- m_dwarf_cu->GetLocationTable(m_data);
-
- llvm::MCRegisterInfo *MRI = abi ? &abi->GetMCRegisterInfo() : nullptr;
- llvm::DIDumpOptions DumpOpts;
- DumpOpts.RecoverableErrorHandler = [&](llvm::Error E) {
- s->AsRawOstream() << "error: " << toString(std::move(E));
- };
- loctable_up->dumpLocationList(
- &offset, s->AsRawOstream(),
- llvm::object::SectionedAddress{m_loclist_addresses->cu_file_addr}, MRI,
- DummyDWARFObject(m_data.GetByteOrder() == eByteOrderLittle), nullptr,
- DumpOpts, s->GetIndentLevel() + 2);
- } else {
- // We have a normal location that contains DW_OP location opcodes
- DumpLocation(s, m_data, level, abi);
- }
-}
static bool ReadRegisterValueAsScalar(RegisterContext *reg_ctx,
lldb::RegisterKind reg_kind,
@@ -409,11 +338,10 @@ static offset_t GetOpcodeDataSize(const DataExtractor &data,
return LLDB_INVALID_OFFSET;
}
-lldb::addr_t DWARFExpression::GetLocation_DW_OP_addr(uint32_t op_addr_idx,
+lldb::addr_t DWARFExpression::GetLocation_DW_OP_addr(const DWARFUnit *dwarf_cu,
+ uint32_t op_addr_idx,
bool &error) const {
error = false;
- if (IsLocationList())
- return LLDB_INVALID_ADDRESS;
lldb::offset_t offset = 0;
uint32_t curr_op_addr_idx = 0;
while (m_data.ValidOffset(offset)) {
@@ -423,19 +351,18 @@ lldb::addr_t DWARFExpression::GetLocation_DW_OP_addr(uint32_t op_addr_idx,
const lldb::addr_t op_file_addr = m_data.GetAddress(&offset);
if (curr_op_addr_idx == op_addr_idx)
return op_file_addr;
- else
- ++curr_op_addr_idx;
+ ++curr_op_addr_idx;
} else if (op == DW_OP_GNU_addr_index || op == DW_OP_addrx) {
uint64_t index = m_data.GetULEB128(&offset);
if (curr_op_addr_idx == op_addr_idx) {
- if (!m_dwarf_cu) {
+ if (!dwarf_cu) {
error = true;
break;
}
- return ReadAddressFromDebugAddrSection(m_dwarf_cu, index);
- } else
- ++curr_op_addr_idx;
+ return dwarf_cu->ReadAddressFromDebugAddrSection(index);
+ }
+ ++curr_op_addr_idx;
} else {
const offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op);
if (op_arg_size == LLDB_INVALID_OFFSET) {
@@ -449,8 +376,6 @@ lldb::addr_t DWARFExpression::GetLocation_DW_OP_addr(uint32_t op_addr_idx,
}
bool DWARFExpression::Update_DW_OP_addr(lldb::addr_t file_addr) {
- if (IsLocationList())
- return false;
lldb::offset_t offset = 0;
while (m_data.ValidOffset(offset)) {
const uint8_t op = m_data.GetU8(&offset);
@@ -487,11 +412,6 @@ bool DWARFExpression::Update_DW_OP_addr(lldb::addr_t file_addr) {
}
bool DWARFExpression::ContainsThreadLocalStorage() const {
- // We are assuming for now that any thread local variable will not have a
- // location list. This has been true for all thread local variables we have
- // seen so far produced by any compiler.
- if (IsLocationList())
- return false;
lldb::offset_t offset = 0;
while (m_data.ValidOffset(offset)) {
const uint8_t op = m_data.GetU8(&offset);
@@ -501,27 +421,18 @@ bool DWARFExpression::ContainsThreadLocalStorage() const {
const offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op);
if (op_arg_size == LLDB_INVALID_OFFSET)
return false;
- else
- offset += op_arg_size;
+ offset += op_arg_size;
}
return false;
}
bool DWARFExpression::LinkThreadLocalStorage(
- lldb::ModuleSP new_module_sp,
std::function<lldb::addr_t(lldb::addr_t file_addr)> const
&link_address_callback) {
- // We are assuming for now that any thread local variable will not have a
- // location list. This has been true for all thread local variables we have
- // seen so far produced by any compiler.
- if (IsLocationList())
- return false;
-
const uint32_t addr_byte_size = m_data.GetAddressByteSize();
// We have to make a copy of the data as we don't know if this data is from a
// read only memory mapped buffer, so we duplicate all of the data first,
// then modify it, and if all goes well, we then replace the data for this
// expression.
-
// Make en encoder that contains a copy of the location expression data so we
// can write the address into the buffer using the correct byte order.
DataEncoder encoder(m_data.GetDataStart(), m_data.GetByteSize(),
@@ -593,42 +504,10 @@ bool DWARFExpression::LinkThreadLocalStorage(
}
}
- // If we linked the TLS address correctly, update the module so that when the
- // expression is evaluated it can resolve the file address to a load address
- // and read the
- // TLS data
- m_module_wp = new_module_sp;
m_data.SetData(encoder.GetDataBuffer());
return true;
}
-bool DWARFExpression::LocationListContainsAddress(addr_t func_load_addr,
- lldb::addr_t addr) const {
- if (func_load_addr == LLDB_INVALID_ADDRESS || addr == LLDB_INVALID_ADDRESS)
- return false;
-
- if (!IsLocationList())
- return false;
-
- return GetLocationExpression(func_load_addr, addr) != llvm::None;
-}
-
-bool DWARFExpression::DumpLocationForAddress(Stream *s,
- lldb::DescriptionLevel level,
- addr_t func_load_addr,
- addr_t address, ABI *abi) {
- if (!IsLocationList()) {
- DumpLocation(s, m_data, level, abi);
- return true;
- }
- if (llvm::Optional<DataExtractor> expr =
- GetLocationExpression(func_load_addr, address)) {
- DumpLocation(s, *expr, level, abi);
- return true;
- }
- return false;
-}
-
static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack,
ExecutionContext *exe_ctx,
RegisterContext *reg_ctx,
@@ -824,10 +703,10 @@ static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack,
// TODO: Add support for DW_OP_push_object_address within a DW_OP_entry_value
// subexpresion whenever llvm does.
Value result;
- const DWARFExpression &param_expr = matched_param->LocationInCaller;
+ const DWARFExpressionList &param_expr = matched_param->LocationInCaller;
if (!param_expr.Evaluate(&parent_exe_ctx,
parent_frame->GetRegisterContext().get(),
- /*loclist_base_load_addr=*/LLDB_INVALID_ADDRESS,
+ LLDB_INVALID_ADDRESS,
/*initial_value_ptr=*/nullptr,
/*object_address_ptr=*/nullptr, result, error_ptr)) {
LLDB_LOG(log,
@@ -839,63 +718,6 @@ static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack,
return true;
}
-bool DWARFExpression::Evaluate(ExecutionContextScope *exe_scope,
- lldb::addr_t loclist_base_load_addr,
- const Value *initial_value_ptr,
- const Value *object_address_ptr, Value &result,
- Status *error_ptr) const {
- ExecutionContext exe_ctx(exe_scope);
- return Evaluate(&exe_ctx, nullptr, loclist_base_load_addr, initial_value_ptr,
- object_address_ptr, result, error_ptr);
-}
-
-bool DWARFExpression::Evaluate(ExecutionContext *exe_ctx,
- RegisterContext *reg_ctx,
- lldb::addr_t func_load_addr,
- const Value *initial_value_ptr,
- const Value *object_address_ptr, Value &result,
- Status *error_ptr) const {
- ModuleSP module_sp = m_module_wp.lock();
-
- if (IsLocationList()) {
- Address pc;
- StackFrame *frame = nullptr;
- if (!reg_ctx || !reg_ctx->GetPCForSymbolication(pc)) {
- frame = exe_ctx->GetFramePtr();
- if (!frame)
- return false;
- RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
- if (!reg_ctx_sp)
- return false;
- reg_ctx_sp->GetPCForSymbolication(pc);
- }
-
- if (func_load_addr != LLDB_INVALID_ADDRESS) {
- if (!pc.IsValid()) {
- if (error_ptr)
- error_ptr->SetErrorString("Invalid PC in frame.");
- return false;
- }
-
- Target *target = exe_ctx->GetTargetPtr();
- if (llvm::Optional<DataExtractor> expr = GetLocationExpression(
- func_load_addr, pc.GetLoadAddress(target))) {
- return DWARFExpression::Evaluate(
- exe_ctx, reg_ctx, module_sp, *expr, m_dwarf_cu, m_reg_kind,
- initial_value_ptr, object_address_ptr, result, error_ptr);
- }
- }
- if (error_ptr)
- error_ptr->SetErrorString("variable not available");
- return false;
- }
-
- // Not a location list, just a single expression.
- return DWARFExpression::Evaluate(exe_ctx, reg_ctx, module_sp, m_data,
- m_dwarf_cu, m_reg_kind, initial_value_ptr,
- object_address_ptr, result, error_ptr);
-}
-
namespace {
/// The location description kinds described by the DWARF v5
/// specification. Composite locations are handled out-of-band and
@@ -2670,7 +2492,7 @@ bool DWARFExpression::Evaluate(
return false;
}
uint64_t index = opcodes.GetULEB128(&offset);
- lldb::addr_t value = ReadAddressFromDebugAddrSection(dwarf_cu, index);
+ lldb::addr_t value = dwarf_cu->ReadAddressFromDebugAddrSection(index);
stack.push_back(Scalar(value));
stack.back().SetValueType(Value::ValueType::FileAddress);
} break;
@@ -2690,7 +2512,7 @@ bool DWARFExpression::Evaluate(
return false;
}
uint64_t index = opcodes.GetULEB128(&offset);
- lldb::addr_t value = ReadAddressFromDebugAddrSection(dwarf_cu, index);
+ lldb::addr_t value = dwarf_cu->ReadAddressFromDebugAddrSection(index);
stack.push_back(Scalar(value));
} break;
@@ -2743,61 +2565,16 @@ bool DWARFExpression::Evaluate(
return true; // Return true on success
}
-static DataExtractor ToDataExtractor(const llvm::DWARFLocationExpression &loc,
- ByteOrder byte_order, uint32_t addr_size) {
- auto buffer_sp =
- std::make_shared<DataBufferHeap>(loc.Expr.data(), loc.Expr.size());
- return DataExtractor(buffer_sp, byte_order, addr_size);
-}
-
-bool DWARFExpression::DumpLocations(Stream *s, lldb::DescriptionLevel level,
- addr_t load_function_start, addr_t addr,
- ABI *abi) {
- if (!IsLocationList()) {
- DumpLocation(s, m_data, level, abi);
- return true;
- }
- bool dump_all = addr == LLDB_INVALID_ADDRESS;
- llvm::ListSeparator separator;
- auto callback = [&](llvm::DWARFLocationExpression loc) -> bool {
- if (loc.Range &&
- (dump_all || (loc.Range->LowPC <= addr && addr < loc.Range->HighPC))) {
- uint32_t addr_size = m_data.GetAddressByteSize();
- DataExtractor data = ToDataExtractor(loc, m_data.GetByteOrder(),
- m_data.GetAddressByteSize());
- s->AsRawOstream() << separator;
- s->PutCString("[");
- s->AsRawOstream() << llvm::format_hex(loc.Range->LowPC,
- 2 + 2 * addr_size);
- s->PutCString(", ");
- s->AsRawOstream() << llvm::format_hex(loc.Range->HighPC,
- 2 + 2 * addr_size);
- s->PutCString(") -> ");
- DumpLocation(s, data, level, abi);
- return dump_all;
- }
- return true;
- };
- if (!GetLocationExpressions(load_function_start, callback))
- return false;
- return true;
-}
-
-bool DWARFExpression::GetLocationExpressions(
- addr_t load_function_start,
- llvm::function_ref<bool(llvm::DWARFLocationExpression)> callback) const {
- if (load_function_start == LLDB_INVALID_ADDRESS)
- return false;
-
- Log *log = GetLog(LLDBLog::Expressions);
-
+bool DWARFExpression::ParseDWARFLocationList(
+ const DWARFUnit *dwarf_cu, const DataExtractor &data,
+ DWARFExpressionList *location_list) {
+ location_list->Clear();
std::unique_ptr<llvm::DWARFLocationTable> loctable_up =
- m_dwarf_cu->GetLocationTable(m_data);
-
- uint64_t offset = 0;
+ dwarf_cu->GetLocationTable(data);
+ Log *log = GetLog(LLDBLog::Expressions);
auto lookup_addr =
[&](uint32_t index) -> llvm::Optional<llvm::object::SectionedAddress> {
- addr_t address = ReadAddressFromDebugAddrSection(m_dwarf_cu, index);
+ addr_t address = dwarf_cu->ReadAddressFromDebugAddrSection(index);
if (address == LLDB_INVALID_ADDRESS)
return llvm::None;
return llvm::object::SectionedAddress{address};
@@ -2807,18 +2584,17 @@ bool DWARFExpression::GetLocationExpressions(
LLDB_LOG_ERROR(log, loc.takeError(), "{0}");
return true;
}
- if (loc->Range) {
- // This relocates low_pc and high_pc by adding the difference between the
- // function file address, and the actual address it is loaded in memory.
- addr_t slide = load_function_start - m_loclist_addresses->func_file_addr;
- loc->Range->LowPC += slide;
- loc->Range->HighPC += slide;
- }
- return callback(*loc);
+ auto buffer_sp =
+ std::make_shared<DataBufferHeap>(loc->Expr.data(), loc->Expr.size());
+ DWARFExpression expr = DWARFExpression(DataExtractor(
+ buffer_sp, data.GetByteOrder(), data.GetAddressByteSize()));
+ location_list->AddExpression(loc->Range->LowPC, loc->Range->HighPC, expr);
+ return true;
};
llvm::Error error = loctable_up->visitAbsoluteLocationList(
- offset, llvm::object::SectionedAddress{m_loclist_addresses->cu_file_addr},
+ 0, llvm::object::SectionedAddress{dwarf_cu->GetBaseAddress()},
lookup_addr, process_list);
+ location_list->Sort();
if (error) {
LLDB_LOG_ERROR(log, std::move(error), "{0}");
return false;
@@ -2826,23 +2602,8 @@ bool DWARFExpression::GetLocationExpressions(
return true;
}
-llvm::Optional<DataExtractor>
-DWARFExpression::GetLocationExpression(addr_t load_function_start,
- addr_t addr) const {
- llvm::Optional<DataExtractor> data;
- auto callback = [&](llvm::DWARFLocationExpression loc) {
- if (loc.Range && loc.Range->LowPC <= addr && addr < loc.Range->HighPC) {
- data = ToDataExtractor(loc, m_data.GetByteOrder(),
- m_data.GetAddressByteSize());
- }
- return !data;
- };
- GetLocationExpressions(load_function_start, callback);
- return data;
-}
-
-bool DWARFExpression::MatchesOperand(StackFrame &frame,
- const Instruction::Operand &operand) {
+bool DWARFExpression::MatchesOperand(
+ StackFrame &frame, const Instruction::Operand &operand) const {
using namespace OperandMatchers;
RegisterContextSP reg_ctx_sp = frame.GetRegisterContext();
@@ -2850,28 +2611,7 @@ bool DWARFExpression::MatchesOperand(StackFrame &frame,
return false;
}
- DataExtractor opcodes;
- if (IsLocationList()) {
- SymbolContext sc = frame.GetSymbolContext(eSymbolContextFunction);
- if (!sc.function)
- return false;
-
- addr_t load_function_start =
- sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
- if (load_function_start == LLDB_INVALID_ADDRESS)
- return false;
-
- addr_t pc = frame.GetFrameCodeAddressForSymbolication().GetLoadAddress(
- frame.CalculateTarget().get());
-
- if (llvm::Optional<DataExtractor> expr =
- GetLocationExpression(load_function_start, pc))
- opcodes = std::move(*expr);
- else
- return false;
- } else
- opcodes = m_data;
-
+ DataExtractor opcodes(m_data);
lldb::offset_t op_offset = 0;
uint8_t opcode = opcodes.GetU8(&op_offset);
@@ -2879,7 +2619,7 @@ bool DWARFExpression::MatchesOperand(StackFrame &frame,
if (opcode == DW_OP_fbreg) {
int64_t offset = opcodes.GetSLEB128(&op_offset);
- DWARFExpression *fb_expr = frame.GetFrameBaseExpression(nullptr);
+ DWARFExpressionList *fb_expr = frame.GetFrameBaseExpression(nullptr);
if (!fb_expr) {
return false;
}
diff --git a/lldb/source/Expression/DWARFExpressionList.cpp b/lldb/source/Expression/DWARFExpressionList.cpp
new file mode 100644
index 000000000000..5cf722c42fa9
--- /dev/null
+++ b/lldb/source/Expression/DWARFExpressionList.cpp
@@ -0,0 +1,248 @@
+//===-- DWARFExpressionList.cpp -------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Expression/DWARFExpressionList.h"
+#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool DWARFExpressionList::IsAlwaysValidSingleExpr() const {
+ return GetAlwaysValidExpr() != nullptr;
+}
+
+const DWARFExpression * DWARFExpressionList::GetAlwaysValidExpr() const {
+ if (m_exprs.GetSize() != 1)
+ return nullptr;
+ const auto *expr = m_exprs.GetEntryAtIndex(0);
+ if (expr->base == 0 && expr->size == LLDB_INVALID_ADDRESS)
+ return &expr->data;
+ return nullptr;
+}
+
+bool DWARFExpressionList::AddExpression(addr_t base, addr_t end,
+ DWARFExpression expr) {
+ if (IsAlwaysValidSingleExpr() || base >= end)
+ return false;
+ m_exprs.Append({base, end - base, expr});
+ return true;
+}
+
+bool DWARFExpressionList::GetExpressionData(DataExtractor &data,
+ lldb::addr_t func_load_addr,
+ lldb::addr_t file_addr) const {
+ if (const DWARFExpression *expr =
+ GetExpressionAtAddress(func_load_addr, file_addr))
+ return expr->GetExpressionData(data);
+ return false;
+}
+
+bool DWARFExpressionList::ContainsAddress(lldb::addr_t func_load_addr,
+ lldb::addr_t addr) const {
+ if (IsAlwaysValidSingleExpr())
+ return true;
+ return GetExpressionAtAddress(func_load_addr, addr) != nullptr;
+}
+
+const DWARFExpression *
+DWARFExpressionList::GetExpressionAtAddress(lldb::addr_t func_load_addr,
+ lldb::addr_t load_addr) const {
+ if (const DWARFExpression *expr = GetAlwaysValidExpr())
+ return expr;
+ if (func_load_addr == LLDB_INVALID_ADDRESS)
+ func_load_addr = m_func_file_addr;
+ addr_t addr = load_addr - func_load_addr + m_func_file_addr;
+ uint32_t index = m_exprs.FindEntryIndexThatContains(addr);
+ if (index == UINT32_MAX)
+ return nullptr;
+ return &m_exprs.GetEntryAtIndex(index)->data;
+}
+
+DWARFExpression *
+DWARFExpressionList::GetMutableExpressionAtAddress(lldb::addr_t func_load_addr,
+ lldb::addr_t load_addr) {
+ if (IsAlwaysValidSingleExpr())
+ return &m_exprs.GetMutableEntryAtIndex(0)->data;
+ if (func_load_addr == LLDB_INVALID_ADDRESS)
+ func_load_addr = m_func_file_addr;
+ addr_t addr = load_addr - func_load_addr + m_func_file_addr;
+ uint32_t index = m_exprs.FindEntryIndexThatContains(addr);
+ if (index == UINT32_MAX)
+ return nullptr;
+ return &m_exprs.GetMutableEntryAtIndex(index)->data;
+}
+
+bool DWARFExpressionList::ContainsThreadLocalStorage() const {
+ // We are assuming for now that any thread local variable will not have a
+ // location list. This has been true for all thread local variables we have
+ // seen so far produced by any compiler.
+ if (!IsAlwaysValidSingleExpr())
+ return false;
+
+ const DWARFExpression &expr = m_exprs.GetEntryRef(0).data;
+ return expr.ContainsThreadLocalStorage();
+}
+
+bool DWARFExpressionList::LinkThreadLocalStorage(
+ lldb::ModuleSP new_module_sp,
+ std::function<lldb::addr_t(lldb::addr_t file_addr)> const
+ &link_address_callback) {
+ // We are assuming for now that any thread local variable will not have a
+ // location list. This has been true for all thread local variables we have
+ // seen so far produced by any compiler.
+ if (!IsAlwaysValidSingleExpr())
+ return false;
+
+ DWARFExpression &expr = m_exprs.GetEntryRef(0).data;
+ // If we linked the TLS address correctly, update the module so that when the
+ // expression is evaluated it can resolve the file address to a load address
+ // and read the TLS data
+ if (expr.LinkThreadLocalStorage(link_address_callback))
+ m_module_wp = new_module_sp;
+ return true;
+}
+
+bool DWARFExpressionList::MatchesOperand(
+ StackFrame &frame, const Instruction::Operand &operand) const {
+ RegisterContextSP reg_ctx_sp = frame.GetRegisterContext();
+ if (!reg_ctx_sp) {
+ return false;
+ }
+ const DWARFExpression *expr = nullptr;
+ if (IsAlwaysValidSingleExpr())
+ expr = &m_exprs.GetEntryAtIndex(0)->data;
+ else {
+ SymbolContext sc = frame.GetSymbolContext(eSymbolContextFunction);
+ if (!sc.function)
+ return false;
+
+ addr_t load_function_start =
+ sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
+ if (load_function_start == LLDB_INVALID_ADDRESS)
+ return false;
+
+ addr_t pc = frame.GetFrameCodeAddressForSymbolication().GetFileAddress();
+ expr = GetExpressionAtAddress(LLDB_INVALID_ADDRESS, pc);
+ }
+ if (!expr)
+ return false;
+ return expr->MatchesOperand(frame, operand);
+}
+
+bool DWARFExpressionList::DumpLocations(Stream *s, lldb::DescriptionLevel level,
+ lldb::addr_t func_load_addr,
+ lldb::addr_t file_addr,
+ ABI *abi) const {
+ llvm::raw_ostream &os = s->AsRawOstream();
+ llvm::ListSeparator separator;
+ if (const DWARFExpression *expr = GetAlwaysValidExpr()) {
+ expr->DumpLocation(s, level, abi);
+ return true;
+ }
+ for (const Entry &entry : *this) {
+ addr_t load_base = entry.GetRangeBase() + func_load_addr - m_func_file_addr;
+ addr_t load_end = entry.GetRangeEnd() + func_load_addr - m_func_file_addr;
+ if (file_addr != LLDB_INVALID_ADDRESS &&
+ (file_addr < load_base || file_addr >= load_end))
+ continue;
+ const auto &expr = entry.data;
+ DataExtractor data;
+ expr.GetExpressionData(data);
+ uint32_t addr_size = data.GetAddressByteSize();
+
+ os << separator;
+ os << "[";
+ os << llvm::format_hex(load_base, 2 + 2 * addr_size);
+ os << ", ";
+ os << llvm::format_hex(load_end, 2 + 2 * addr_size);
+ os << ") -> ";
+ expr.DumpLocation(s, level, abi);
+ if (file_addr != LLDB_INVALID_ADDRESS)
+ break;
+ }
+ return true;
+}
+
+void DWARFExpressionList::GetDescription(Stream *s,
+ lldb::DescriptionLevel level,
+ ABI *abi) const {
+ llvm::raw_ostream &os = s->AsRawOstream();
+ if (IsAlwaysValidSingleExpr()) {
+ m_exprs.Back()->data.DumpLocation(s, level, abi);
+ return;
+ }
+ os << llvm::format("0x%8.8" PRIx64 ": ", 0);
+ for (const Entry &entry : *this) {
+ const auto &expr = entry.data;
+ DataExtractor data;
+ expr.GetExpressionData(data);
+ uint32_t addr_size = data.GetAddressByteSize();
+ os << "\n";
+ os.indent(s->GetIndentLevel() + 2);
+ os << "[";
+ llvm::DWARFFormValue::dumpAddress(os, addr_size, entry.GetRangeBase());
+ os << ", ";
+ llvm::DWARFFormValue::dumpAddress(os, addr_size, entry.GetRangeEnd());
+ os << "): ";
+ expr.DumpLocation(s, level, abi);
+ }
+}
+
+bool DWARFExpressionList::Evaluate(ExecutionContext *exe_ctx,
+ RegisterContext *reg_ctx,
+ lldb::addr_t func_load_addr,
+ const Value *initial_value_ptr,
+ const Value *object_address_ptr,
+ Value &result, Status *error_ptr) const {
+ ModuleSP module_sp = m_module_wp.lock();
+ DataExtractor data;
+ RegisterKind reg_kind;
+ DWARFExpression expr;
+ if (IsAlwaysValidSingleExpr()) {
+ expr = m_exprs.Back()->data;
+ } else {
+ Address pc;
+ StackFrame *frame = nullptr;
+ if (!reg_ctx || !reg_ctx->GetPCForSymbolication(pc)) {
+ if (exe_ctx)
+ frame = exe_ctx->GetFramePtr();
+ if (!frame)
+ return false;
+ RegisterContextSP reg_ctx_sp = frame->GetRegisterContext();
+ if (!reg_ctx_sp)
+ return false;
+ reg_ctx_sp->GetPCForSymbolication(pc);
+ }
+
+ if (!pc.IsValid()) {
+ if (error_ptr)
+ error_ptr->SetErrorString("Invalid PC in frame.");
+ return false;
+ }
+ addr_t pc_load_addr = pc.GetLoadAddress(exe_ctx->GetTargetPtr());
+ const DWARFExpression *entry =
+ GetExpressionAtAddress(func_load_addr, pc_load_addr);
+ if (!entry) {
+ if (error_ptr) {
+ error_ptr->SetErrorString("variable not available");
+ }
+ return false;
+ }
+ expr = *entry;
+ }
+ expr.GetExpressionData(data);
+ reg_kind = expr.GetRegisterKind();
+ return DWARFExpression::Evaluate(exe_ctx, reg_ctx, module_sp, data,
+ m_dwarf_cu, reg_kind, initial_value_ptr,
+ object_address_ptr, result, error_ptr);
+}
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 49fa72f7112d..6b710084faf7 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -200,7 +200,9 @@ Status IRExecutionUnit::DisassembleFunction(Stream &stream,
UINT32_MAX, false, false);
InstructionList &instruction_list = disassembler_sp->GetInstructionList();
- instruction_list.Dump(&stream, true, true, &exe_ctx);
+ instruction_list.Dump(&stream, true, true, /*show_control_flow_kind=*/true,
+ &exe_ctx);
+
return ret;
}
diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp
index 9ee2d983ddfc..965a96b7f909 100644
--- a/lldb/source/Expression/Materializer.cpp
+++ b/lldb/source/Expression/Materializer.cpp
@@ -520,7 +520,7 @@ public:
if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize(scope)) {
if (data.GetByteSize() == 0 &&
- !m_variable_sp->LocationExpression().IsValid()) {
+ !m_variable_sp->LocationExpressionList().IsValid()) {
err.SetErrorStringWithFormat("the variable '%s' has no location, "
"it may have been optimized out",
m_variable_sp->GetName().AsCString());
diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp
index c92fec53a55e..910d740625e9 100644
--- a/lldb/source/Interpreter/CommandObject.cpp
+++ b/lldb/source/Interpreter/CommandObject.cpp
@@ -547,7 +547,7 @@ CommandObject::LookupArgumentName(llvm::StringRef arg_name) {
const ArgumentTableEntry *table = GetArgumentTable();
for (int i = 0; i < eArgTypeLastArg; ++i)
if (arg_name == table[i].arg_name)
- return_type = g_arguments_data[i].arg_type;
+ return_type = GetArgumentTable()[i].arg_type;
return return_type;
}
@@ -924,14 +924,14 @@ const char *CommandObject::GetArgumentTypeAsCString(
const lldb::CommandArgumentType arg_type) {
assert(arg_type < eArgTypeLastArg &&
"Invalid argument type passed to GetArgumentTypeAsCString");
- return g_arguments_data[arg_type].arg_name;
+ return GetArgumentTable()[arg_type].arg_name;
}
const char *CommandObject::GetArgumentDescriptionAsCString(
const lldb::CommandArgumentType arg_type) {
assert(arg_type < eArgTypeLastArg &&
"Invalid argument type passed to GetArgumentDescriptionAsCString");
- return g_arguments_data[arg_type].help_text;
+ return GetArgumentTable()[arg_type].help_text;
}
Target &CommandObject::GetDummyTarget() {
@@ -1041,7 +1041,7 @@ static llvm::StringRef arch_helper() {
return g_archs_help.GetString();
}
-CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = {
+static constexpr CommandObject::ArgumentTableEntry g_arguments_data[] = {
// clang-format off
{ eArgTypeAddress, "address", CommandCompletions::eNoCompletion, { nullptr, false }, "A valid address in the target program's execution space." },
{ eArgTypeAddressOrExpression, "address-expression", CommandCompletions::eNoCompletion, { nullptr, false }, "An expression that resolves to an address." },
@@ -1134,17 +1134,18 @@ CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = {
{ eArgTypeSaveCoreStyle, "corefile-style", CommandCompletions::eNoCompletion, { nullptr, false }, "The type of corefile that lldb will try to create, dependant on this target's capabilities." },
{ eArgTypeLogHandler, "log-handler", CommandCompletions::eNoCompletion, { nullptr, false }, "The log handle that will be used to write out log messages." },
{ eArgTypeSEDStylePair, "substitution-pair", CommandCompletions::eNoCompletion, { nullptr, false }, "A sed-style pattern and target pair." },
+ { eArgTypeRecognizerID, "frame-recognizer-id", CommandCompletions::eNoCompletion, { nullptr, false }, "The ID for a stack frame recognizer." },
{ eArgTypeConnectURL, "process-connect-url", CommandCompletions::eNoCompletion, { nullptr, false }, "A URL-style specification for a remote connection." },
{ eArgTypeTargetID, "target-id", CommandCompletions::eNoCompletion, { nullptr, false }, "The index ID for an lldb Target." },
{ eArgTypeStopHookID, "stop-hook-id", CommandCompletions::eNoCompletion, { nullptr, false }, "The ID you receive when you create a stop-hook." }
// clang-format on
};
+static_assert(
+ (sizeof(g_arguments_data) / sizeof(CommandObject::ArgumentTableEntry)) ==
+ eArgTypeLastArg,
+ "g_arguments_data out of sync with CommandArgumentType enumeration");
+
const CommandObject::ArgumentTableEntry *CommandObject::GetArgumentTable() {
- // If this assertion fires, then the table above is out of date with the
- // CommandArgumentType enumeration
- static_assert((sizeof(CommandObject::g_arguments_data) /
- sizeof(CommandObject::ArgumentTableEntry)) == eArgTypeLastArg,
- "");
- return CommandObject::g_arguments_data;
+ return g_arguments_data;
}
diff --git a/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h
index e74b9126404e..a9c2ed9c2f14 100644
--- a/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h
+++ b/lldb/source/Plugins/ABI/X86/ABIWindows_x86_64.h
@@ -40,10 +40,15 @@ public:
bool RegisterIsVolatile(const lldb_private::RegisterInfo *reg_info) override;
- // In Windows_x86_64 ABI, stack will always be maintained 16-byte aligned
+ // In Windows_x86_64 ABI requires that the stack will be maintained 16-byte
+ // aligned.
+ // When ntdll invokes callbacks such as KiUserExceptionDispatcher or
+ // KiUserCallbackDispatcher, those functions won't have a properly 16-byte
+ // aligned stack - but tolerate unwinding through them by relaxing the
+ // requirement to 8 bytes.
bool CallFrameAddressIsValid(lldb::addr_t cfa) override {
- if (cfa & (16ull - 1ull))
- return false; // Not 16 byte aligned
+ if (cfa & (8ull - 1ull))
+ return false; // Not 8 byte aligned
if (cfa == 0)
return false; // Zero is not a valid stack address
return true;
diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
index c85c66442510..a774d5b61cfe 100644
--- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
+++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp
@@ -1181,11 +1181,7 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch,
// If any AArch64 variant, enable latest ISA with all extensions.
if (triple.isAArch64()) {
- features_str += "+v9.3a,";
- std::vector<llvm::StringRef> features;
- // Get all possible features
- llvm::AArch64::getExtensionFeatures(-1, features);
- features_str += llvm::join(features, ",");
+ features_str += "+all,";
if (triple.getVendor() == llvm::Triple::Apple)
cpu = "apple-latest";
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
index cc45871bcd71..4305a9982343 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -772,10 +772,6 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context) {
return;
AddContextClassType(context, TypeFromUser(m_ctx_obj->GetCompilerType()));
-
- m_struct_vars->m_object_pointer_type =
- TypeFromUser(ctx_obj_ptr->GetCompilerType());
-
return;
}
@@ -810,18 +806,6 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context) {
class_qual_type.getAsString());
AddContextClassType(context, class_user_type);
-
- if (method_decl->isInstance()) {
- // self is a pointer to the object
-
- QualType class_pointer_type =
- method_decl->getASTContext().getPointerType(class_qual_type);
-
- TypeFromUser self_user_type(class_pointer_type.getAsOpaquePtr(),
- function_decl_ctx.GetTypeSystem());
-
- m_struct_vars->m_object_pointer_type = self_user_type;
- }
return;
}
@@ -852,8 +836,6 @@ void ClangExpressionDeclMap::LookUpLldbClass(NameSearchContext &context) {
ClangUtil::GetQualType(pointee_type).getAsString());
AddContextClassType(context, pointee_type);
- TypeFromUser this_user_type(this_type->GetFullCompilerType());
- m_struct_vars->m_object_pointer_type = this_user_type;
}
}
@@ -869,10 +851,6 @@ void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context) {
return;
AddOneType(context, TypeFromUser(m_ctx_obj->GetCompilerType()));
-
- m_struct_vars->m_object_pointer_type =
- TypeFromUser(ctx_obj_ptr->GetCompilerType());
-
return;
}
@@ -917,28 +895,6 @@ void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context) {
ClangUtil::ToString(interface_type));
AddOneType(context, class_user_type);
-
- if (method_decl->isInstanceMethod()) {
- // self is a pointer to the object
-
- QualType class_pointer_type =
- method_decl->getASTContext().getObjCObjectPointerType(
- QualType(interface_type, 0));
-
- TypeFromUser self_user_type(class_pointer_type.getAsOpaquePtr(),
- function_decl_ctx.GetTypeSystem());
-
- m_struct_vars->m_object_pointer_type = self_user_type;
- } else {
- // self is a Class pointer
- QualType class_type = method_decl->getASTContext().getObjCClassType();
-
- TypeFromUser self_user_type(class_type.getAsOpaquePtr(),
- function_decl_ctx.GetTypeSystem());
-
- m_struct_vars->m_object_pointer_type = self_user_type;
- }
-
return;
}
// This branch will get hit if we are executing code in the context of
@@ -981,10 +937,6 @@ void ClangExpressionDeclMap::LookUpLldbObjCClass(NameSearchContext &context) {
TypeFromUser class_user_type(self_clang_type);
AddOneType(context, class_user_type);
-
- TypeFromUser self_user_type(self_type->GetFullCompilerType());
-
- m_struct_vars->m_object_pointer_type = self_user_type;
}
void ClangExpressionDeclMap::LookupLocalVarNamespace(
@@ -1485,15 +1437,14 @@ bool ClangExpressionDeclMap::GetVariableValue(VariableSP &var,
return false;
}
- DWARFExpression &var_location_expr = var->LocationExpression();
+ DWARFExpressionList &var_location_list = var->LocationExpressionList();
Target *target = m_parser_vars->m_exe_ctx.GetTargetPtr();
Status err;
if (var->GetLocationIsConstantValueData()) {
DataExtractor const_value_extractor;
-
- if (var_location_expr.GetExpressionData(const_value_extractor)) {
+ if (var_location_list.GetExpressionData(const_value_extractor)) {
var_location = Value(const_value_extractor.GetDataStart(),
const_value_extractor.GetByteSize());
var_location.SetValueType(Value::ValueType::HostAddress);
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
index e39dc587bc43..f968f859cc72 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
@@ -353,7 +353,7 @@ private:
/// The following values contain layout information for the materialized
/// struct, but are not specific to a single materialization
struct StructVars {
- StructVars() : m_result_name(), m_object_pointer_type(nullptr, nullptr) {}
+ StructVars() = default;
lldb::offset_t m_struct_alignment =
0; ///< The alignment of the struct in bytes.
@@ -364,8 +364,6 @@ private:
/// added since).
ConstString
m_result_name; ///< The name of the result variable ($1, for example)
- TypeFromUser m_object_pointer_type; ///< The type of the "this" variable, if
- ///one exists
};
std::unique_ptr<StructVars> m_struct_vars;
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index 82f825871593..89bee3e000c0 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -911,6 +911,14 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
"std::map iterator synthetic children",
ConstString("^std::__[[:alnum:]]+::__map_iterator<.+>$"), stl_synth_flags,
true);
+
+ AddCXXSynthetic(
+ cpp_category_sp,
+ lldb_private::formatters::
+ LibCxxUnorderedMapIteratorSyntheticFrontEndCreator,
+ "std::unordered_map iterator synthetic children",
+ ConstString("^std::__[[:alnum:]]+::__hash_map_(const_)?iterator<.+>$"),
+ stl_synth_flags, true);
}
static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
index eaaa16413b1e..3b04b3a1b2ac 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.cpp
@@ -27,6 +27,7 @@
#include "Plugins/LanguageRuntime/CPlusPlus/CPPLanguageRuntime.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
+#include "lldb/lldb-enumerations.h"
#include <tuple>
using namespace lldb;
@@ -283,6 +284,22 @@ bool lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEnd::Update() {
llvm::dyn_cast_or_null<TypeSystemClang>(pair_type.GetTypeSystem());
if (!ast_ctx)
return false;
+
+ // Mimick layout of std::__tree_iterator::__ptr_ and read it in
+ // from process memory.
+ //
+ // The following shows the contiguous block of memory:
+ //
+ // +-----------------------------+ class __tree_end_node
+ // __ptr_ | pointer __left_; |
+ // +-----------------------------+ class __tree_node_base
+ // | pointer __right_; |
+ // | __parent_pointer __parent_; |
+ // | bool __is_black_; |
+ // +-----------------------------+ class __tree_node
+ // | __node_value_type __value_; | <<< our key/value pair
+ // +-----------------------------+
+ //
CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(
ConstString(),
{{"ptr0",
@@ -359,6 +376,156 @@ lldb_private::formatters::LibCxxMapIteratorSyntheticFrontEndCreator(
: nullptr);
}
+lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
+ LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
+ : SyntheticChildrenFrontEnd(*valobj_sp) {
+ if (valobj_sp)
+ Update();
+}
+
+bool lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
+ Update() {
+ m_pair_sp.reset();
+ m_iter_ptr = nullptr;
+
+ ValueObjectSP valobj_sp = m_backend.GetSP();
+ if (!valobj_sp)
+ return false;
+
+ TargetSP target_sp(valobj_sp->GetTargetSP());
+
+ if (!target_sp)
+ return false;
+
+ if (!valobj_sp)
+ return false;
+
+ auto exprPathOptions = ValueObject::GetValueForExpressionPathOptions()
+ .DontCheckDotVsArrowSyntax()
+ .SetSyntheticChildrenTraversal(
+ ValueObject::GetValueForExpressionPathOptions::
+ SyntheticChildrenTraversal::None);
+
+ // This must be a ValueObject* because it is a child of the ValueObject we
+ // are producing children for it if were a ValueObjectSP, we would end up
+ // with a loop (iterator -> synthetic -> child -> parent == iterator) and
+ // that would in turn leak memory by never allowing the ValueObjects to die
+ // and free their memory.
+ m_iter_ptr =
+ valobj_sp
+ ->GetValueForExpressionPath(".__i_.__node_", nullptr, nullptr,
+ exprPathOptions, nullptr)
+ .get();
+
+ if (m_iter_ptr) {
+ auto iter_child(
+ valobj_sp->GetChildMemberWithName(ConstString("__i_"), true));
+ if (!iter_child) {
+ m_iter_ptr = nullptr;
+ return false;
+ }
+
+ CompilerType node_type(iter_child->GetCompilerType()
+ .GetTypeTemplateArgument(0)
+ .GetPointeeType());
+
+ CompilerType pair_type(node_type.GetTypeTemplateArgument(0));
+
+ std::string name;
+ uint64_t bit_offset_ptr;
+ uint32_t bitfield_bit_size_ptr;
+ bool is_bitfield_ptr;
+
+ pair_type = pair_type.GetFieldAtIndex(
+ 0, name, &bit_offset_ptr, &bitfield_bit_size_ptr, &is_bitfield_ptr);
+ if (!pair_type) {
+ m_iter_ptr = nullptr;
+ return false;
+ }
+
+ uint64_t addr = m_iter_ptr->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ m_iter_ptr = nullptr;
+
+ if (addr == 0 || addr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ TypeSystemClang *ast_ctx =
+ llvm::dyn_cast_or_null<TypeSystemClang>(pair_type.GetTypeSystem());
+ if (!ast_ctx)
+ return false;
+
+ // Mimick layout of std::__hash_iterator::__node_ and read it in
+ // from process memory.
+ //
+ // The following shows the contiguous block of memory:
+ //
+ // +-----------------------------+ class __hash_node_base
+ // __node_ | __next_pointer __next_; |
+ // +-----------------------------+ class __hash_node
+ // | size_t __hash_; |
+ // | __node_value_type __value_; | <<< our key/value pair
+ // +-----------------------------+
+ //
+ CompilerType tree_node_type = ast_ctx->CreateStructForIdentifier(
+ ConstString(),
+ {{"__next_",
+ ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType()},
+ {"__hash_", ast_ctx->GetBasicType(lldb::eBasicTypeUnsignedLongLong)},
+ {"__value_", pair_type}});
+ llvm::Optional<uint64_t> size = tree_node_type.GetByteSize(nullptr);
+ if (!size)
+ return false;
+ WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0));
+ ProcessSP process_sp(target_sp->GetProcessSP());
+ Status error;
+ process_sp->ReadMemory(addr, buffer_sp->GetBytes(),
+ buffer_sp->GetByteSize(), error);
+ if (error.Fail())
+ return false;
+ DataExtractor extractor(buffer_sp, process_sp->GetByteOrder(),
+ process_sp->GetAddressByteSize());
+ auto pair_sp = CreateValueObjectFromData(
+ "pair", extractor, valobj_sp->GetExecutionContextRef(), tree_node_type);
+ if (pair_sp)
+ m_pair_sp = pair_sp->GetChildAtIndex(2, true);
+ }
+
+ return false;
+}
+
+size_t lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
+ CalculateNumChildren() {
+ return 2;
+}
+
+lldb::ValueObjectSP lldb_private::formatters::
+ LibCxxUnorderedMapIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
+ if (m_pair_sp)
+ return m_pair_sp->GetChildAtIndex(idx, true);
+ return lldb::ValueObjectSP();
+}
+
+bool lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
+ MightHaveChildren() {
+ return true;
+}
+
+size_t lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEnd::
+ GetIndexOfChildWithName(ConstString name) {
+ if (name == "first")
+ return 0;
+ if (name == "second")
+ return 1;
+ return UINT32_MAX;
+}
+
+SyntheticChildrenFrontEnd *
+lldb_private::formatters::LibCxxUnorderedMapIteratorSyntheticFrontEndCreator(
+ CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
+ return (valobj_sp ? new LibCxxUnorderedMapIteratorSyntheticFrontEnd(valobj_sp)
+ : nullptr);
+}
+
/*
(lldb) fr var ibeg --raw --ptr-depth 1 -T
(std::__1::__wrap_iter<int *>) ibeg = {
@@ -547,101 +714,77 @@ bool lldb_private::formatters::LibcxxContainerSummaryProvider(
}
/// The field layout in a libc++ string (cap, side, data or data, size, cap).
-enum LibcxxStringLayoutMode {
- eLibcxxStringLayoutModeCSD = 0,
- eLibcxxStringLayoutModeDSC = 1,
- eLibcxxStringLayoutModeInvalid = 0xffff
-};
+namespace {
+enum class StringLayout { CSD, DSC };
+}
/// Determine the size in bytes of \p valobj (a libc++ std::string object) and
/// extract its data payload. Return the size + payload pair.
// TODO: Support big-endian architectures.
static llvm::Optional<std::pair<uint64_t, ValueObjectSP>>
ExtractLibcxxStringInfo(ValueObject &valobj) {
- ValueObjectSP dataval_sp(valobj.GetChildAtIndexPath({0, 0, 0, 0}));
- if (!dataval_sp)
+ ValueObjectSP valobj_r_sp =
+ valobj.GetChildMemberWithName(ConstString("__r_"), /*can_create=*/true);
+ if (!valobj_r_sp || !valobj_r_sp->GetError().Success())
return {};
- if (!dataval_sp->GetError().Success())
+
+ // __r_ is a compressed_pair of the actual data and the allocator. The data we
+ // want is in the first base class.
+ ValueObjectSP valobj_r_base_sp =
+ valobj_r_sp->GetChildAtIndex(0, /*can_create=*/true);
+ if (!valobj_r_base_sp)
return {};
- ValueObjectSP layout_decider(
- dataval_sp->GetChildAtIndexPath(llvm::ArrayRef<size_t>({0, 0})));
+ ValueObjectSP valobj_rep_sp = valobj_r_base_sp->GetChildMemberWithName(
+ ConstString("__value_"), /*can_create=*/true);
+ if (!valobj_rep_sp)
+ return {};
- // this child should exist
- if (!layout_decider)
+ ValueObjectSP l = valobj_rep_sp->GetChildMemberWithName(ConstString("__l"),
+ /*can_create=*/true);
+ if (!l)
return {};
- ConstString g_data_name("__data_");
- ConstString g_size_name("__size_");
+ StringLayout layout = l->GetIndexOfChildWithName(ConstString("__data_")) == 0
+ ? StringLayout::DSC
+ : StringLayout::CSD;
+
bool short_mode = false; // this means the string is in short-mode and the
// data is stored inline
bool using_bitmasks = true; // Whether the class uses bitmasks for the mode
// flag (pre-D123580).
uint64_t size;
- LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name)
- ? eLibcxxStringLayoutModeDSC
- : eLibcxxStringLayoutModeCSD;
uint64_t size_mode_value = 0;
- ValueObjectSP short_sp(dataval_sp->GetChildAtIndex(1, true));
+ ValueObjectSP short_sp = valobj_rep_sp->GetChildMemberWithName(
+ ConstString("__s"), /*can_create=*/true);
if (!short_sp)
return {};
- ValueObjectSP short_fields_sp;
ValueObjectSP is_long =
short_sp->GetChildMemberWithName(ConstString("__is_long_"), true);
- if (is_long) {
- short_fields_sp = short_sp;
- } else {
- // After D128285, we need to access the `__is_long_` and `__size_` fields
- // from a packed anonymous struct
- short_fields_sp = short_sp->GetChildAtIndex(0, true);
- is_long = short_sp->GetChildMemberWithName(ConstString("__is_long_"), true);
- }
+ ValueObjectSP size_sp =
+ short_sp->GetChildAtNamePath({ConstString("__size_")});
+ if (!size_sp)
+ return {};
if (is_long) {
using_bitmasks = false;
short_mode = !is_long->GetValueAsUnsigned(/*fail_value=*/0);
- if (ValueObjectSP size_member =
- dataval_sp->GetChildAtNamePath({ConstString("__s"), ConstString("__size_")}))
- size = size_member->GetValueAsUnsigned(/*fail_value=*/0);
- else
- return {};
- } else if (layout == eLibcxxStringLayoutModeDSC) {
- llvm::SmallVector<size_t, 3> size_mode_locations[] = {
- {1, 2}, // Post-c3d0205ee771 layout. This was in use for only a brief
- // period, so we can delete it if it becomes a burden.
- {1, 1, 0},
- {1, 1, 1},
- };
- ValueObjectSP size_mode;
- for (llvm::ArrayRef<size_t> loc : size_mode_locations) {
- size_mode = dataval_sp->GetChildAtIndexPath(loc);
- if (size_mode && size_mode->GetName() == g_size_name)
- break;
- }
-
- if (!size_mode)
- return {};
-
- size_mode_value = (size_mode->GetValueAsUnsigned(0));
- short_mode = ((size_mode_value & 0x80) == 0);
+ size = size_sp->GetValueAsUnsigned(/*fail_value=*/0);
} else {
- ValueObjectSP size_mode(dataval_sp->GetChildAtIndexPath({1, 0, 0}));
- if (!size_mode)
- return {};
-
- size_mode_value = (size_mode->GetValueAsUnsigned(0));
- short_mode = ((size_mode_value & 1) == 0);
+ // The string mode is encoded in the size field.
+ size_mode_value = size_sp->GetValueAsUnsigned(0);
+ uint8_t mode_mask = layout == StringLayout::DSC ? 0x80 : 1;
+ short_mode = (size_mode_value & mode_mask) == 0;
}
if (short_mode) {
ValueObjectSP location_sp =
- short_sp->GetChildMemberWithName(g_data_name, true);
+ short_sp->GetChildMemberWithName(ConstString("__data_"), true);
if (using_bitmasks)
- size = (layout == eLibcxxStringLayoutModeDSC)
- ? size_mode_value
- : ((size_mode_value >> 1) % 256);
+ size = (layout == StringLayout::DSC) ? size_mode_value
+ : ((size_mode_value >> 1) % 256);
// When the small-string optimization takes place, the data must fit in the
// inline string buffer (23 bytes on x86_64/Darwin). If it doesn't, it's
@@ -656,10 +799,6 @@ ExtractLibcxxStringInfo(ValueObject &valobj) {
return std::make_pair(size, location_sp);
}
- ValueObjectSP l(dataval_sp->GetChildAtIndex(0, true));
- if (!l)
- return {};
-
// we can use the layout_decider object as the data pointer
ValueObjectSP location_sp =
l->GetChildMemberWithName(ConstString("__data_"), /*can_create=*/true);
@@ -667,19 +806,11 @@ ExtractLibcxxStringInfo(ValueObject &valobj) {
l->GetChildMemberWithName(ConstString("__size_"), /*can_create=*/true);
ValueObjectSP capacity_vo =
l->GetChildMemberWithName(ConstString("__cap_"), /*can_create=*/true);
- if (!capacity_vo) {
- // After D128285, we need to access the `__cap_` field from a packed
- // anonymous struct
- if (ValueObjectSP packed_fields_sp = l->GetChildAtIndex(0, true)) {
- ValueObjectSP capacity_vo = packed_fields_sp->GetChildMemberWithName(
- ConstString("__cap_"), /*can_create=*/true);
- }
- }
if (!size_vo || !location_sp || !capacity_vo)
return {};
size = size_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
uint64_t capacity = capacity_vo->GetValueAsUnsigned(LLDB_INVALID_OFFSET);
- if (!using_bitmasks && layout == eLibcxxStringLayoutModeCSD)
+ if (!using_bitmasks && layout == StringLayout::CSD)
capacity *= 2;
if (size == LLDB_INVALID_OFFSET || capacity == LLDB_INVALID_OFFSET ||
capacity < size)
diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
index b4e789e65b51..b5ade4af8574 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
+++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
@@ -103,6 +103,56 @@ SyntheticChildrenFrontEnd *
LibCxxMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
+/// Formats libcxx's std::unordered_map iterators
+///
+/// In raw form a std::unordered_map::iterator is represented as follows:
+///
+/// (lldb) var it --raw --ptr-depth 1
+/// (std::__1::__hash_map_iterator<
+/// std::__1::__hash_iterator<
+/// std::__1::__hash_node<
+/// std::__1::__hash_value_type<
+/// std::__1::basic_string<char, std::__1::char_traits<char>,
+/// std::__1::allocator<char> >, std::__1::basic_string<char,
+/// std::__1::char_traits<char>, std::__1::allocator<char> > >,
+/// void *> *> >)
+/// it = {
+/// __i_ = {
+/// __node_ = 0x0000600001700040 {
+/// __next_ = 0x0000600001704000
+/// }
+/// }
+/// }
+class LibCxxUnorderedMapIteratorSyntheticFrontEnd
+ : public SyntheticChildrenFrontEnd {
+public:
+ LibCxxUnorderedMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
+
+ ~LibCxxUnorderedMapIteratorSyntheticFrontEnd() override = default;
+
+ size_t CalculateNumChildren() override;
+
+ lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
+
+ bool Update() override;
+
+ bool MightHaveChildren() override;
+
+ size_t GetIndexOfChildWithName(ConstString name) override;
+
+private:
+ ValueObject *m_iter_ptr = nullptr; ///< Held, not owned. Child of iterator
+ ///< ValueObject supplied at construction.
+
+ lldb::ValueObjectSP m_pair_sp; ///< ValueObject for the key/value pair
+ ///< that the iterator currently points
+ ///< to.
+};
+
+SyntheticChildrenFrontEnd *
+LibCxxUnorderedMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
+ lldb::ValueObjectSP);
+
SyntheticChildrenFrontEnd *
LibCxxVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
index a2522372f5af..9fe222eceedc 100644
--- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
+++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
@@ -40,6 +40,8 @@ typedef struct ar_hdr {
using namespace lldb;
using namespace lldb_private;
+using namespace llvm::object;
+
LLDB_PLUGIN_DEFINE(ObjectContainerBSDArchive)
ObjectContainerBSDArchive::Object::Object() : ar_name() {}
@@ -55,6 +57,74 @@ void ObjectContainerBSDArchive::Object::Clear() {
file_size = 0;
}
+lldb::offset_t ObjectContainerBSDArchive::Object::ExtractFromThin(
+ const DataExtractor &data, lldb::offset_t offset,
+ llvm::StringRef stringTable) {
+ size_t ar_name_len = 0;
+ std::string str;
+ char *err;
+
+ // File header
+ //
+ // The common format is as follows.
+ //
+ // Offset Length Name Format
+ // 0 16 File name ASCII right padded with spaces (no spaces
+ // allowed in file name)
+ // 16 12 File mod Decimal as cstring right padded with
+ // spaces
+ // 28 6 Owner ID Decimal as cstring right padded with
+ // spaces
+ // 34 6 Group ID Decimal as cstring right padded with
+ // spaces
+ // 40 8 File mode Octal as cstring right padded with
+ // spaces
+ // 48 10 File byte size Decimal as cstring right padded with
+ // spaces
+ // 58 2 File magic 0x60 0x0A
+
+ // Make sure there is enough data for the file header and bail if not
+ if (!data.ValidOffsetForDataOfSize(offset, 60))
+ return LLDB_INVALID_OFFSET;
+
+ str.assign((const char *)data.GetData(&offset, 16), 16);
+ if (!(llvm::StringRef(str).startswith("//") || stringTable.empty())) {
+ // Strip off any trailing spaces.
+ const size_t last_pos = str.find_last_not_of(' ');
+ if (last_pos != std::string::npos) {
+ if (last_pos + 1 < 16)
+ str.erase(last_pos + 1);
+ }
+ int start = strtoul(str.c_str() + 1, &err, 10);
+ int end = stringTable.find('\n', start);
+ str.assign(stringTable.data() + start, end - start - 1);
+ ar_name.SetCString(str.c_str());
+ }
+
+ str.assign((const char *)data.GetData(&offset, 12), 12);
+ modification_time = strtoul(str.c_str(), &err, 10);
+
+ str.assign((const char *)data.GetData(&offset, 6), 6);
+ uid = strtoul(str.c_str(), &err, 10);
+
+ str.assign((const char *)data.GetData(&offset, 6), 6);
+ gid = strtoul(str.c_str(), &err, 10);
+
+ str.assign((const char *)data.GetData(&offset, 8), 8);
+ mode = strtoul(str.c_str(), &err, 8);
+
+ str.assign((const char *)data.GetData(&offset, 10), 10);
+ size = strtoul(str.c_str(), &err, 10);
+
+ str.assign((const char *)data.GetData(&offset, 2), 2);
+ if (str == ARFMAG) {
+ file_offset = offset;
+ file_size = size - ar_name_len;
+ return offset;
+ }
+ return LLDB_INVALID_OFFSET;
+}
+
lldb::offset_t
ObjectContainerBSDArchive::Object::Extract(const DataExtractor &data,
lldb::offset_t offset) {
@@ -136,9 +206,10 @@ ObjectContainerBSDArchive::Object::Extract(const DataExtractor &data,
ObjectContainerBSDArchive::Archive::Archive(const lldb_private::ArchSpec &arch,
const llvm::sys::TimePoint<> &time,
lldb::offset_t file_offset,
- lldb_private::DataExtractor &data)
+ lldb_private::DataExtractor &data,
+ ArchiveType archive_type)
: m_arch(arch), m_modification_time(time), m_file_offset(file_offset),
- m_objects(), m_data(data) {}
+ m_objects(), m_data(data), m_archive_type(archive_type) {}
ObjectContainerBSDArchive::Archive::~Archive() = default;
@@ -163,6 +234,48 @@ size_t ObjectContainerBSDArchive::Archive::ParseObjects() {
// Now sort all of the object name pointers
m_object_name_to_index_map.Sort();
+ } else if (str == ThinArchiveMagic) {
+ Object obj;
+ size_t obj_idx;
+
+ // Retrieve symbol table
+ offset = obj.ExtractFromThin(data, offset, "");
+ if (offset == LLDB_INVALID_OFFSET)
+ return m_objects.size();
+ obj_idx = m_objects.size();
+ m_objects.push_back(obj);
+ // Insert all of the C strings out of order for now...
+ m_object_name_to_index_map.Append(obj.ar_name, obj_idx);
+ offset += obj.file_size;
+ obj.Clear();
+
+ // Retrieve string table
+ offset = obj.ExtractFromThin(data, offset, "");
+ if (offset == LLDB_INVALID_OFFSET)
+ return m_objects.size();
+ obj_idx = m_objects.size();
+ m_objects.push_back(obj);
+ // Insert all of the C strings out of order for now...
+ m_object_name_to_index_map.Append(obj.ar_name, obj_idx);
+ // Extract string table
+ llvm::StringRef strtab((const char *)data.GetData(&offset, obj.size),
+ obj.size);
+ obj.Clear();
+
+ // Retrieve object files
+ do {
+ offset = obj.ExtractFromThin(data, offset, strtab);
+ if (offset == LLDB_INVALID_OFFSET)
+ break;
+ obj_idx = m_objects.size();
+ m_objects.push_back(obj);
+ // Insert all of the C strings out of order for now...
+ m_object_name_to_index_map.Append(obj.ar_name, obj_idx);
+ obj.Clear();
+ } while (data.ValidOffset(offset));
+
+ // Now sort all of the object name pointers
+ m_object_name_to_index_map.Sort();
}
return m_objects.size();
}
@@ -237,8 +350,9 @@ ObjectContainerBSDArchive::Archive::shared_ptr
ObjectContainerBSDArchive::Archive::ParseAndCacheArchiveForFile(
const FileSpec &file, const ArchSpec &arch,
const llvm::sys::TimePoint<> &time, lldb::offset_t file_offset,
- DataExtractor &data) {
- shared_ptr archive_sp(new Archive(arch, time, file_offset, data));
+ DataExtractor &data, ArchiveType archive_type) {
+ shared_ptr archive_sp(
+ new Archive(arch, time, file_offset, data, archive_type));
if (archive_sp) {
const size_t num_objects = archive_sp->ParseObjects();
if (num_objects > 0) {
@@ -288,7 +402,8 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance(
// contents for the archive and cache it
DataExtractor data;
data.SetData(data_sp, data_offset, length);
- if (file && data_sp && ObjectContainerBSDArchive::MagicBytesMatch(data)) {
+ ArchiveType archive_type = ObjectContainerBSDArchive::MagicBytesMatch(data);
+ if (file && data_sp && archive_type != ArchiveType::Invalid) {
LLDB_SCOPED_TIMERF(
"ObjectContainerBSDArchive::CreateInstance (module = %s, file = "
"%p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")",
@@ -312,7 +427,7 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance(
std::unique_ptr<ObjectContainerBSDArchive> container_up(
new ObjectContainerBSDArchive(module_sp, archive_data_sp,
archive_data_offset, file, file_offset,
- length));
+ length, archive_type));
if (container_up) {
if (archive_sp) {
@@ -331,7 +446,8 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance(
if (archive_sp) {
std::unique_ptr<ObjectContainerBSDArchive> container_up(
new ObjectContainerBSDArchive(module_sp, data_sp, data_offset, file,
- file_offset, length));
+ file_offset, length,
+ archive_sp->GetArchiveType()));
if (container_up) {
// We already have this archive in our cache, use it
@@ -343,23 +459,35 @@ ObjectContainer *ObjectContainerBSDArchive::CreateInstance(
return nullptr;
}
-bool ObjectContainerBSDArchive::MagicBytesMatch(const DataExtractor &data) {
+ArchiveType
+ObjectContainerBSDArchive::MagicBytesMatch(const DataExtractor &data) {
uint32_t offset = 0;
const char *armag = (const char *)data.PeekData(offset, sizeof(ar_hdr));
- if (armag && ::strncmp(armag, ARMAG, SARMAG) == 0) {
+ if (armag == nullptr)
+ return ArchiveType::Invalid;
+ if (::strncmp(armag, ARMAG, SARMAG) == 0) {
armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG;
if (strncmp(armag, ARFMAG, 2) == 0)
- return true;
+ return ArchiveType::Archive;
+ } else if (::strncmp(armag, ThinArchiveMagic, strlen(ThinArchiveMagic)) ==
+ 0) {
+ armag += offsetof(struct ar_hdr, ar_fmag) + strlen(ThinArchiveMagic);
+ if (strncmp(armag, ARFMAG, 2) == 0) {
+ return ArchiveType::ThinArchive;
+ }
}
- return false;
+ return ArchiveType::Invalid;
}
ObjectContainerBSDArchive::ObjectContainerBSDArchive(
const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
lldb::offset_t data_offset, const lldb_private::FileSpec *file,
- lldb::offset_t file_offset, lldb::offset_t size)
+ lldb::offset_t file_offset, lldb::offset_t size, ArchiveType archive_type)
: ObjectContainer(module_sp, file, file_offset, size, data_sp, data_offset),
- m_archive_sp() {}
+ m_archive_sp() {
+ m_archive_type = archive_type;
+}
+
void ObjectContainerBSDArchive::SetArchive(Archive::shared_ptr &archive_sp) {
m_archive_sp = archive_sp;
}
@@ -373,7 +501,7 @@ bool ObjectContainerBSDArchive::ParseHeader() {
if (module_sp) {
m_archive_sp = Archive::ParseAndCacheArchiveForFile(
m_file, module_sp->GetArchitecture(),
- module_sp->GetModificationTime(), m_offset, m_data);
+ module_sp->GetModificationTime(), m_offset, m_data, m_archive_type);
}
// Clear the m_data that contains the entire archive data and let our
// m_archive_sp hold onto the data.
@@ -407,6 +535,19 @@ void ObjectContainerBSDArchive::Dump(Stream *s) const {
s->EOL();
}
+FileSpec GetChildFileSpecificationsFromThin(llvm::StringRef childPath,
+ const FileSpec &parentFileSpec) {
+ llvm::SmallString<128> FullPath;
+ if (llvm::sys::path::is_absolute(childPath)) {
+ FullPath = childPath;
+ } else {
+ FullPath = parentFileSpec.GetDirectory().GetStringRef();
+ llvm::sys::path::append(FullPath, childPath);
+ }
+ FileSpec child = FileSpec(FullPath.str(), llvm::sys::path::Style::posix);
+ return child;
+}
+
ObjectFileSP ObjectContainerBSDArchive::GetObjectFile(const FileSpec *file) {
ModuleSP module_sp(GetModule());
if (module_sp) {
@@ -414,6 +555,22 @@ ObjectFileSP ObjectContainerBSDArchive::GetObjectFile(const FileSpec *file) {
Object *object = m_archive_sp->FindObject(
module_sp->GetObjectName(), module_sp->GetObjectModificationTime());
if (object) {
+ if (m_archive_type == ArchiveType::ThinArchive) {
+ // Set file to child object file
+ FileSpec child = GetChildFileSpecificationsFromThin(
+ object->ar_name.GetStringRef(), m_file);
+ lldb::offset_t file_offset = 0;
+ lldb::offset_t file_size = object->size;
+ std::shared_ptr<DataBuffer> child_data_sp =
+ FileSystem::Instance().CreateDataBuffer(child, file_size,
+ file_offset);
+ if (child_data_sp->GetByteSize() != object->file_size)
+ return ObjectFileSP();
+ lldb::offset_t data_offset = 0;
+ return ObjectFile::FindPlugin(
+ module_sp, &child, m_offset + object->file_offset,
+ object->file_size, child_data_sp, data_offset);
+ }
lldb::offset_t data_offset = object->file_offset;
return ObjectFile::FindPlugin(
module_sp, file, m_offset + object->file_offset, object->file_size,
@@ -434,7 +591,8 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications(
// contents for the archive and cache it
DataExtractor data;
data.SetData(data_sp, data_offset, data_sp->GetByteSize());
- if (!file || !data_sp || !ObjectContainerBSDArchive::MagicBytesMatch(data))
+ ArchiveType archive_type = ObjectContainerBSDArchive::MagicBytesMatch(data);
+ if (!file || !data_sp || archive_type == ArchiveType::Invalid)
return 0;
const size_t initial_count = specs.GetSize();
@@ -449,7 +607,7 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications(
if (data_sp) {
data.SetData(data_sp, 0, data_sp->GetByteSize());
archive_sp = Archive::ParseAndCacheArchiveForFile(
- file, ArchSpec(), file_mod_time, file_offset, data);
+ file, ArchSpec(), file_mod_time, file_offset, data, archive_type);
}
}
@@ -458,6 +616,24 @@ size_t ObjectContainerBSDArchive::GetModuleSpecifications(
for (size_t idx = 0; idx < num_objects; ++idx) {
const Object *object = archive_sp->GetObjectAtIndex(idx);
if (object) {
+ if (archive_sp->GetArchiveType() == ArchiveType::ThinArchive) {
+ if (object->ar_name.IsEmpty())
+ continue;
+ FileSpec child = GetChildFileSpecificationsFromThin(
+ object->ar_name.GetStringRef(), file);
+ if (ObjectFile::GetModuleSpecifications(child, 0, object->file_size,
+ specs)) {
+ ModuleSpec &spec =
+ specs.GetModuleSpecRefAtIndex(specs.GetSize() - 1);
+ llvm::sys::TimePoint<> object_mod_time(
+ std::chrono::seconds(object->modification_time));
+ spec.GetObjectName() = object->ar_name;
+ spec.SetObjectOffset(0);
+ spec.SetObjectSize(object->file_size);
+ spec.GetObjectModificationTime() = object_mod_time;
+ }
+ continue;
+ }
const lldb::offset_t object_file_offset =
file_offset + object->file_offset;
if (object->file_offset < file_size && file_size > object_file_offset) {
diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
index 21106d7b8590..ace072cbe149 100644
--- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
+++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
@@ -15,19 +15,24 @@
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/FileSpec.h"
+#include "llvm/Object/Archive.h"
#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Path.h"
#include <map>
#include <memory>
#include <mutex>
+enum class ArchiveType { Invalid, Archive, ThinArchive };
+
class ObjectContainerBSDArchive : public lldb_private::ObjectContainer {
public:
ObjectContainerBSDArchive(const lldb::ModuleSP &module_sp,
lldb::DataBufferSP &data_sp,
lldb::offset_t data_offset,
const lldb_private::FileSpec *file,
- lldb::offset_t offset, lldb::offset_t length);
+ lldb::offset_t offset, lldb::offset_t length,
+ ArchiveType archive_type);
~ObjectContainerBSDArchive() override;
@@ -54,7 +59,7 @@ public:
lldb::offset_t length,
lldb_private::ModuleSpecList &specs);
- static bool MagicBytesMatch(const lldb_private::DataExtractor &data);
+ static ArchiveType MagicBytesMatch(const lldb_private::DataExtractor &data);
// Member Functions
bool ParseHeader() override;
@@ -78,6 +83,10 @@ protected:
void Clear();
+ lldb::offset_t ExtractFromThin(const lldb_private::DataExtractor &data,
+ lldb::offset_t offset,
+ llvm::StringRef stringTable);
+
lldb::offset_t Extract(const lldb_private::DataExtractor &data,
lldb::offset_t offset);
/// Object name in the archive.
@@ -112,7 +121,7 @@ protected:
Archive(const lldb_private::ArchSpec &arch,
const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset,
- lldb_private::DataExtractor &data);
+ lldb_private::DataExtractor &data, ArchiveType archive_type);
~Archive();
@@ -127,7 +136,7 @@ protected:
static Archive::shared_ptr ParseAndCacheArchiveForFile(
const lldb_private::FileSpec &file, const lldb_private::ArchSpec &arch,
const llvm::sys::TimePoint<> &mod_time, lldb::offset_t file_offset,
- lldb_private::DataExtractor &data);
+ lldb_private::DataExtractor &data, ArchiveType archive_type);
size_t GetNumObjects() const { return m_objects.size(); }
@@ -156,6 +165,8 @@ protected:
lldb_private::DataExtractor &GetData() { return m_data; }
+ ArchiveType GetArchiveType() { return m_archive_type; }
+
protected:
typedef lldb_private::UniqueCStringMap<uint32_t> ObjectNameToIndexMap;
// Member Variables
@@ -167,11 +178,14 @@ protected:
lldb_private::DataExtractor m_data; ///< The data for this object container
///so we don't lose data if the .a files
///gets modified
+ ArchiveType m_archive_type;
};
void SetArchive(Archive::shared_ptr &archive_sp);
Archive::shared_ptr m_archive_sp;
+
+ ArchiveType m_archive_type;
};
#endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_BSD_ARCHIVE_OBJECTCONTAINERBSDARCHIVE_H
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 28ccfbe3d6e6..f9fb36890d5a 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -3386,8 +3386,7 @@ size_t ObjectFileELF::ReadSectionData(Section *section,
auto buffer_sp =
std::make_shared<DataBufferHeap>(Decompressor->getDecompressedSize(), 0);
if (auto error = Decompressor->decompress(
- {reinterpret_cast<char *>(buffer_sp->GetBytes()),
- size_t(buffer_sp->GetByteSize())})) {
+ {buffer_sp->GetBytes(), size_t(buffer_sp->GetByteSize())})) {
GetModule()->ReportWarning(
"Decompression of section '%s' failed: %s",
section->GetName().GetCString(),
diff --git a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp
index 1c10efed9564..44c708676e52 100644
--- a/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp
+++ b/lldb/source/Plugins/ObjectFile/PDB/ObjectFilePDB.cpp
@@ -137,8 +137,6 @@ size_t ObjectFilePDB::GetModuleSpecifications(
case PDB_Machine::x86:
module_arch.SetTriple("i386-pc-windows");
specs.Append(module_spec);
- module_arch.SetTriple("i686-pc-windows");
- specs.Append(module_spec);
break;
case PDB_Machine::ArmNT:
module_arch.SetTriple("armv7-pc-windows");
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 700e6ebdf84c..c44ace96dd55 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -2727,7 +2727,7 @@ bool GDBRemoteCommunicationClient::SetCurrentThread(uint64_t tid,
m_curr_pid = ret->pid;
m_curr_tid = ret->tid;
}
- return ret.hasValue();
+ return ret.has_value();
}
bool GDBRemoteCommunicationClient::SetCurrentThreadForRun(uint64_t tid,
@@ -2742,7 +2742,7 @@ bool GDBRemoteCommunicationClient::SetCurrentThreadForRun(uint64_t tid,
m_curr_pid_run = ret->pid;
m_curr_tid_run = ret->tid;
}
- return ret.hasValue();
+ return ret.has_value();
}
bool GDBRemoteCommunicationClient::GetStopReply(
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index 58ed22187747..d367f75cee0e 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -254,8 +254,6 @@ public:
lldb::addr_t GetShlibInfoAddr();
- bool GetSupportsThreadSuffix();
-
bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info);
uint32_t FindProcesses(const ProcessInstanceInfoMatch &process_match_info,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 2aacac3692be..4b9354371bda 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2292,7 +2292,7 @@ DWARFASTParserClang::ParseFunctionFromDWARF(CompileUnit &comp_unit,
int call_file = 0;
int call_line = 0;
int call_column = 0;
- DWARFExpression frame_base;
+ DWARFExpressionList frame_base;
const dw_tag_t tag = die.Tag();
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
index ec074be581b5..06cdd877f7dc 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.cpp
@@ -441,7 +441,7 @@ bool DWARFDIE::GetDIENamesAndRanges(
const char *&name, const char *&mangled, DWARFRangeList &ranges,
int &decl_file, int &decl_line, int &decl_column, int &call_file,
int &call_line, int &call_column,
- lldb_private::DWARFExpression *frame_base) const {
+ lldb_private::DWARFExpressionList *frame_base) const {
if (IsValid()) {
return m_die->GetDIENamesAndRanges(
GetCU(), name, mangled, ranges, decl_file, decl_line, decl_column,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
index 5ee44a763204..7ce9550a081e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDIE.h
@@ -85,11 +85,12 @@ public:
DWARFDIE
GetAttributeValueAsReferenceDIE(const dw_attr_t attr) const;
- bool GetDIENamesAndRanges(const char *&name, const char *&mangled,
- DWARFRangeList &ranges, int &decl_file,
- int &decl_line, int &decl_column, int &call_file,
- int &call_line, int &call_column,
- lldb_private::DWARFExpression *frame_base) const;
+ bool
+ GetDIENamesAndRanges(const char *&name, const char *&mangled,
+ DWARFRangeList &ranges, int &decl_file, int &decl_line,
+ int &decl_column, int &call_file, int &call_line,
+ int &call_column,
+ lldb_private::DWARFExpressionList *frame_base) const;
/// The range of all the children of this DIE.
llvm::iterator_range<child_iterator> children() const;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
index 95c0cb6472c5..c98953640a58 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -231,7 +231,7 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges(
DWARFUnit *cu, const char *&name, const char *&mangled,
DWARFRangeList &ranges, int &decl_file, int &decl_line, int &decl_column,
int &call_file, int &call_line, int &call_column,
- DWARFExpression *frame_base) const {
+ DWARFExpressionList *frame_base) const {
dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;
dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;
std::vector<DWARFDIE> dies;
@@ -345,21 +345,22 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges(
uint32_t block_offset =
form_value.BlockData() - data.GetDataStart();
uint32_t block_length = form_value.Unsigned();
- *frame_base = DWARFExpression(
- module, DataExtractor(data, block_offset, block_length), cu);
+ *frame_base =
+ DWARFExpressionList(module,
+ DWARFExpression(DataExtractor(
+ data, block_offset, block_length)),
+ cu);
} else {
DataExtractor data = cu->GetLocationData();
const dw_offset_t offset = form_value.Unsigned();
if (data.ValidOffset(offset)) {
data = DataExtractor(data, offset, data.GetByteSize() - offset);
- *frame_base = DWARFExpression(module, data, cu);
if (lo_pc != LLDB_INVALID_ADDRESS) {
assert(lo_pc >= cu->GetBaseAddress());
- frame_base->SetLocationListAddresses(cu->GetBaseAddress(),
- lo_pc);
- } else {
+ DWARFExpression::ParseDWARFLocationList(cu, data, frame_base);
+ frame_base->SetFuncFileAddress(lo_pc);
+ } else
set_frame_base_loclist_addr = true;
- }
}
}
}
@@ -384,7 +385,7 @@ bool DWARFDebugInfoEntry::GetDIENamesAndRanges(
if (set_frame_base_loclist_addr) {
dw_addr_t lowest_range_pc = ranges.GetMinRangeBase(0);
assert(lowest_range_pc >= cu->GetBaseAddress());
- frame_base->SetLocationListAddresses(cu->GetBaseAddress(), lowest_range_pc);
+ frame_base->SetFuncFileAddress(lowest_range_pc);
}
if (ranges.IsEmpty() || name == nullptr || mangled == nullptr) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
index 64e86c71ac09..32f653e99a70 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
@@ -104,7 +104,7 @@ public:
DWARFUnit *cu, const char *&name, const char *&mangled,
DWARFRangeList &rangeList, int &decl_file, int &decl_line,
int &decl_column, int &call_file, int &call_line, int &call_column,
- lldb_private::DWARFExpression *frame_base = nullptr) const;
+ lldb_private::DWARFExpressionList *frame_base = nullptr) const;
const DWARFAbbreviationDeclaration *
GetAbbreviationDeclarationPtr(const DWARFUnit *cu) const;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
index 903cd2e38f76..7b4a5d8eca3e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
@@ -579,6 +579,17 @@ void DWARFUnit::SetStrOffsetsBase(dw_offset_t str_offsets_base) {
m_str_offsets_base = str_offsets_base;
}
+dw_addr_t DWARFUnit::ReadAddressFromDebugAddrSection(uint32_t index) const {
+ uint32_t index_size = GetAddressByteSize();
+ dw_offset_t addr_base = GetAddrBase();
+ dw_addr_t offset = addr_base + index * index_size;
+ const DWARFDataExtractor &data =
+ m_dwarf.GetDWARFContext().getOrLoadAddrData();
+ if (data.ValidOffsetForDataOfSize(offset, index_size))
+ return data.GetMaxU64_unchecked(&offset, index_size);
+ return LLDB_INVALID_ADDRESS;
+}
+
// It may be called only with m_die_array_mutex held R/W.
void DWARFUnit::ClearDIEsRWLocked() {
m_die_array.clear();
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
index 265e28b51c99..40a1943b847a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h
@@ -166,6 +166,8 @@ public:
void SetStrOffsetsBase(dw_offset_t str_offsets_base);
virtual void BuildAddressRangeTable(DWARFDebugAranges *debug_aranges) = 0;
+ dw_addr_t ReadAddressFromDebugAddrSection(uint32_t index) const;
+
lldb::ByteOrder GetByteOrder() const;
const DWARFDebugAranges &GetFunctionAranges();
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index c0bf13e0281d..cbc24b1550c7 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -9,6 +9,7 @@
#include "SymbolFileDWARF.h"
#include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Threading.h"
@@ -1885,11 +1886,14 @@ SymbolFileDWARF::GlobalVariableMap &SymbolFileDWARF::GetGlobalAranges() {
for (size_t g = 0; g < num_globals; ++g) {
VariableSP var_sp = globals_sp->GetVariableAtIndex(g);
if (var_sp && !var_sp->GetLocationIsConstantValueData()) {
- const DWARFExpression &location = var_sp->LocationExpression();
+ const DWARFExpressionList &location =
+ var_sp->LocationExpressionList();
Value location_result;
Status error;
- if (location.Evaluate(nullptr, LLDB_INVALID_ADDRESS, nullptr,
- nullptr, location_result, &error)) {
+ ExecutionContext exe_ctx;
+ if (location.Evaluate(&exe_ctx, nullptr, LLDB_INVALID_ADDRESS,
+ nullptr, nullptr, location_result,
+ &error)) {
if (location_result.GetValueType() ==
Value::ValueType::FileAddress) {
lldb::addr_t file_addr =
@@ -3163,7 +3167,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
const char *mangled = nullptr;
Declaration decl;
DWARFFormValue type_die_form;
- DWARFExpression location;
+ DWARFExpressionList location_list(module, DWARFExpression(), die.GetCU());
bool is_external = false;
bool is_artificial = false;
DWARFFormValue const_value_form, location_form;
@@ -3229,16 +3233,15 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
// present in the class declaration and DW_AT_location in the DIE defining
// the member.
bool location_is_const_value_data = false;
- bool has_explicit_location = false;
+ bool has_explicit_location = location_form.IsValid();
bool use_type_size_for_value = false;
if (location_form.IsValid()) {
- has_explicit_location = true;
if (DWARFFormValue::IsBlockForm(location_form.Form())) {
const DWARFDataExtractor &data = die.GetData();
uint32_t block_offset = location_form.BlockData() - data.GetDataStart();
uint32_t block_length = location_form.Unsigned();
- location = DWARFExpression(
+ location_list = DWARFExpressionList(
module, DataExtractor(data, block_offset, block_length), die.GetCU());
} else {
DataExtractor data = die.GetCU()->GetLocationData();
@@ -3247,10 +3250,10 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
offset = die.GetCU()->GetLoclistOffset(offset).value_or(-1);
if (data.ValidOffset(offset)) {
data = DataExtractor(data, offset, data.GetByteSize() - offset);
- location = DWARFExpression(module, data, die.GetCU());
- assert(func_low_pc != LLDB_INVALID_ADDRESS);
- location.SetLocationListAddresses(
- location_form.GetUnit()->GetBaseAddress(), func_low_pc);
+ const DWARFUnit *dwarf_cu = location_form.GetUnit();
+ if (DWARFExpression::ParseDWARFLocationList(dwarf_cu, data,
+ &location_list))
+ location_list.SetFuncFileAddress(func_low_pc);
}
}
} else if (const_value_form.IsValid()) {
@@ -3263,7 +3266,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
uint32_t block_offset =
const_value_form.BlockData() - debug_info_data.GetDataStart();
uint32_t block_length = const_value_form.Unsigned();
- location = DWARFExpression(
+ location_list = DWARFExpressionList(
module, DataExtractor(debug_info_data, block_offset, block_length),
die.GetCU());
} else if (DWARFFormValue::IsDataForm(const_value_form.Form())) {
@@ -3273,7 +3276,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
use_type_size_for_value = true;
} else if (const char *str = const_value_form.AsCString()) {
uint32_t string_length = strlen(str) + 1;
- location = DWARFExpression(
+ location_list = DWARFExpressionList(
module,
DataExtractor(str, string_length, die.GetCU()->GetByteOrder(),
die.GetCU()->GetAddressByteSize()),
@@ -3323,16 +3326,19 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
// with locations like: DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus
// so we need to look through the whole expression.
bool is_static_lifetime =
- has_explicit_mangled || (has_explicit_location && !location.IsValid());
+ has_explicit_mangled ||
+ (has_explicit_location && !location_list.IsValid());
// Check if the location has a DW_OP_addr with any address value...
lldb::addr_t location_DW_OP_addr = LLDB_INVALID_ADDRESS;
if (!location_is_const_value_data) {
bool op_error = false;
- location_DW_OP_addr = location.GetLocation_DW_OP_addr(0, op_error);
+ const DWARFExpression* location = location_list.GetAlwaysValidExpr();
+ if (location)
+ location_DW_OP_addr = location->GetLocation_DW_OP_addr(
+ location_form.GetUnit(), 0, op_error);
if (op_error) {
StreamString strm;
- location.DumpLocationForAddress(&strm, eDescriptionLevelFull, 0, 0,
- nullptr);
+ location->DumpLocation(&strm, eDescriptionLevelFull, nullptr);
GetObjectFile()->GetModule()->ReportError(
"0x%8.8x: %s has an invalid location: %s", die.GetOffset(),
die.GetTagAsCString(), strm.GetData());
@@ -3345,7 +3351,7 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
// Set the module of the expression to the linked module
// instead of the object file so the relocated address can be
// found there.
- location.SetModule(debug_map_symfile->GetObjectFile()->GetModule());
+ location_list.SetModule(debug_map_symfile->GetObjectFile()->GetModule());
if (is_static_lifetime) {
if (is_external)
@@ -3386,7 +3392,9 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
const addr_t exe_file_addr =
exe_symbol->GetAddressRef().GetFileAddress();
if (exe_file_addr != LLDB_INVALID_ADDRESS) {
- if (location.Update_DW_OP_addr(exe_file_addr)) {
+ DWARFExpression *location =
+ location_list.GetMutableExpressionAtAddress();
+ if (location->Update_DW_OP_addr(exe_file_addr)) {
linked_oso_file_addr = true;
symbol_context_scope = exe_symbol;
}
@@ -3404,7 +3412,9 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
debug_map_symfile->LinkOSOFileAddress(this, location_DW_OP_addr);
if (exe_file_addr != LLDB_INVALID_ADDRESS) {
// Update the file address for this variable
- location.Update_DW_OP_addr(exe_file_addr);
+ DWARFExpression *location =
+ location_list.GetMutableExpressionAtAddress();
+ location->Update_DW_OP_addr(exe_file_addr);
} else {
// Variable didn't make it into the final executable
return nullptr;
@@ -3419,8 +3429,8 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
scope = eValueTypeVariableLocal;
if (debug_map_symfile) {
// We need to check for TLS addresses that we need to fixup
- if (location.ContainsThreadLocalStorage()) {
- location.LinkThreadLocalStorage(
+ if (location_list.ContainsThreadLocalStorage()) {
+ location_list.LinkThreadLocalStorage(
debug_map_symfile->GetObjectFile()->GetModule(),
[this, debug_map_symfile](
lldb::addr_t unlinked_file_addr) -> lldb::addr_t {
@@ -3463,14 +3473,17 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
auto type_sp = std::make_shared<SymbolFileType>(
*this, GetUID(type_die_form.Reference()));
- if (use_type_size_for_value && type_sp->GetType())
- location.UpdateValue(const_value_form.Unsigned(),
- type_sp->GetType()->GetByteSize(nullptr).value_or(0),
- die.GetCU()->GetAddressByteSize());
+ if (use_type_size_for_value && type_sp->GetType()) {
+ DWARFExpression *location = location_list.GetMutableExpressionAtAddress();
+ location->UpdateValue(
+ const_value_form.Unsigned(),
+ type_sp->GetType()->GetByteSize(nullptr).getValueOr(0),
+ die.GetCU()->GetAddressByteSize());
+ }
return std::make_shared<Variable>(
die.GetID(), name, mangled, type_sp, scope, symbol_context_scope,
- scope_ranges, &decl, location, is_external, is_artificial,
+ scope_ranges, &decl, location_list, is_external, is_artificial,
location_is_const_value_data, is_static_member);
}
@@ -3755,8 +3768,8 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) {
child.Tag() != DW_TAG_GNU_call_site_parameter)
continue;
- llvm::Optional<DWARFExpression> LocationInCallee;
- llvm::Optional<DWARFExpression> LocationInCaller;
+ llvm::Optional<DWARFExpressionList> LocationInCallee;
+ llvm::Optional<DWARFExpressionList> LocationInCaller;
DWARFAttributes attributes;
const size_t num_attributes = child.GetAttributes(attributes);
@@ -3764,7 +3777,7 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) {
// Parse the location at index \p attr_index within this call site parameter
// DIE, or return None on failure.
auto parse_simple_location =
- [&](int attr_index) -> llvm::Optional<DWARFExpression> {
+ [&](int attr_index) -> llvm::Optional<DWARFExpressionList> {
DWARFFormValue form_value;
if (!attributes.ExtractFormValueAtIndex(attr_index, form_value))
return {};
@@ -3773,9 +3786,9 @@ CollectCallSiteParameters(ModuleSP module, DWARFDIE call_site_die) {
auto data = child.GetData();
uint32_t block_offset = form_value.BlockData() - data.GetDataStart();
uint32_t block_length = form_value.Unsigned();
- return DWARFExpression(module,
- DataExtractor(data, block_offset, block_length),
- child.GetCU());
+ return DWARFExpressionList(
+ module, DataExtractor(data, block_offset, block_length),
+ child.GetCU());
};
for (size_t i = 0; i < num_attributes; ++i) {
@@ -3820,7 +3833,7 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) {
continue;
llvm::Optional<DWARFDIE> call_origin;
- llvm::Optional<DWARFExpression> call_target;
+ llvm::Optional<DWARFExpressionList> call_target;
addr_t return_pc = LLDB_INVALID_ADDRESS;
addr_t call_inst_pc = LLDB_INVALID_ADDRESS;
addr_t low_pc = LLDB_INVALID_ADDRESS;
@@ -3881,7 +3894,7 @@ SymbolFileDWARF::CollectCallEdges(ModuleSP module, DWARFDIE function_die) {
auto data = child.GetData();
uint32_t block_offset = form_value.BlockData() - data.GetDataStart();
uint32_t block_length = form_value.Unsigned();
- call_target = DWARFExpression(
+ call_target = DWARFExpressionList(
module, DataExtractor(data, block_offset, block_length),
child.GetCU());
}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 2403ee2624ea..cfd18f02053b 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -21,6 +21,7 @@
#include "lldb/Core/UniqueCStringMap.h"
#include "lldb/Core/dwarf.h"
+#include "lldb/Expression/DWARFExpressionList.h"
#include "lldb/Symbol/DebugMacros.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolFile.h"
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
index 3ba0079c96e6..3166c8ae65c6 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/DWARFLocationExpression.cpp
@@ -122,7 +122,7 @@ static DWARFExpression MakeLocationExpressionInternal(lldb::ModuleSP module,
DataBufferSP buffer =
std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
DataExtractor extractor(buffer, byte_order, address_size, byte_size);
- DWARFExpression result(module, extractor, nullptr);
+ DWARFExpression result(extractor);
result.SetRegisterKind(register_kind);
return result;
@@ -247,7 +247,7 @@ DWARFExpression lldb_private::npdb::MakeConstantLocationExpression(
.take_front(size);
buffer->CopyData(bytes.data(), size);
DataExtractor extractor(buffer, lldb::eByteOrderLittle, address_size);
- DWARFExpression result(nullptr, extractor, nullptr);
+ DWARFExpression result(extractor);
return result;
}
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
index 7bb7c69eece7..6317b140f7e8 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp
@@ -602,7 +602,7 @@ static RegisterId GetBaseFrameRegister(PdbIndex &index,
}
VariableInfo lldb_private::npdb::GetVariableLocationInfo(
- PdbIndex &index, PdbCompilandSymId var_id, Block &block,
+ PdbIndex &index, PdbCompilandSymId var_id, Block &func_block,
lldb::ModuleSP module) {
CVSymbol sym = index.ReadSymbolRecord(var_id);
@@ -642,14 +642,8 @@ VariableInfo lldb_private::npdb::GetVariableLocationInfo(
Variable::RangeList ranges = MakeRangeList(index, loc.Range, loc.Gaps);
- // TODO: may be better to pass function scope and not lookup it every
- // time? find nearest parent function block
- Block *cur = &block;
- while (cur->GetParent()) {
- cur = cur->GetParent();
- }
PdbCompilandSymId func_scope_id =
- PdbSymUid(cur->GetID()).asCompilandSym();
+ PdbSymUid(func_block.GetID()).asCompilandSym();
CVSymbol func_block_cvs = index.ReadSymbolRecord(func_scope_id);
lldbassert(func_block_cvs.kind() == S_GPROC32 ||
func_block_cvs.kind() == S_LPROC32);
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
index 138c11aaeb43..066bcc89fd3b 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/PdbUtil.h
@@ -142,8 +142,8 @@ LookThroughModifierRecord(llvm::codeview::CVType modifier);
llvm::StringRef DropNameScope(llvm::StringRef name);
VariableInfo GetVariableNameInfo(llvm::codeview::CVSymbol symbol);
-VariableInfo GetVariableLocationInfo(PdbIndex &index, PdbCompilandSymId var_id, Block& block,
- lldb::ModuleSP module);
+VariableInfo GetVariableLocationInfo(PdbIndex &index, PdbCompilandSymId var_id,
+ Block &func_block, lldb::ModuleSP module);
size_t GetTypeSizeForSimpleKind(llvm::codeview::SimpleTypeKind kind);
lldb::BasicType
diff --git a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
index 7dc99818c244..7e10e315be20 100644
--- a/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -823,8 +823,10 @@ VariableSP SymbolFileNativePDB::CreateGlobalVariable(PdbGlobalSymId var_id) {
m_ast->GetOrCreateVariableDecl(var_id);
- DWARFExpression location = MakeGlobalLocationExpression(
- section, offset, GetObjectFile()->GetModule());
+ ModuleSP module_sp = GetObjectFile()->GetModule();
+ DWARFExpressionList location(
+ module_sp, MakeGlobalLocationExpression(section, offset, module_sp),
+ nullptr);
std::string global_name("::");
global_name += name;
@@ -855,8 +857,10 @@ SymbolFileNativePDB::CreateConstantSymbol(PdbGlobalSymId var_id,
Declaration decl;
Variable::RangeList ranges;
ModuleSP module = GetObjectFile()->GetModule();
- DWARFExpression location = MakeConstantLocationExpression(
- constant.Type, tpi, constant.Value, module);
+ DWARFExpressionList location(module,
+ MakeConstantLocationExpression(
+ constant.Type, tpi, constant.Value, module),
+ nullptr);
bool external = false;
bool artificial = false;
@@ -1689,8 +1693,15 @@ VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id,
bool is_param) {
ModuleSP module = GetObjectFile()->GetModule();
Block &block = GetOrCreateBlock(scope_id);
+ // Get function block.
+ Block *func_block = &block;
+ while (func_block->GetParent()) {
+ func_block = func_block->GetParent();
+ }
+ Address addr;
+ func_block->GetStartAddress(addr);
VariableInfo var_info =
- GetVariableLocationInfo(*m_index, var_id, block, module);
+ GetVariableLocationInfo(*m_index, var_id, *func_block, module);
if (!var_info.location || !var_info.ranges)
return nullptr;
@@ -1709,11 +1720,12 @@ VariableSP SymbolFileNativePDB::CreateLocalVariable(PdbCompilandSymId scope_id,
bool artificial = false;
bool location_is_constant_data = false;
bool static_member = false;
+ DWARFExpressionList locaiton_list = DWARFExpressionList(
+ module, *var_info.location, nullptr);
VariableSP var_sp = std::make_shared<Variable>(
toOpaqueUid(var_id), name.c_str(), name.c_str(), sftype, var_scope,
- &block, *var_info.ranges, &decl, *var_info.location, external,
- artificial, location_is_constant_data, static_member);
-
+ &block, *var_info.ranges, &decl, locaiton_list, external, artificial,
+ location_is_constant_data, static_member);
if (!is_param)
m_ast->GetOrCreateVariableDecl(scope_id, var_id);
diff --git a/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp b/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp
index 96e9de704e41..94023737b2a2 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp
@@ -175,7 +175,7 @@ DWARFExpression ConvertPDBLocationToDWARFExpression(
DataBufferSP buffer =
std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
DataExtractor extractor(buffer, byte_order, address_size, byte_size);
- DWARFExpression result(module, extractor, nullptr);
+ DWARFExpression result(extractor);
result.SetRegisterKind(register_kind);
return result;
diff --git a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
index bd3d16aad6c2..baa48532864b 100644
--- a/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ b/lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -1023,8 +1023,11 @@ VariableSP SymbolFilePDB::ParseVariableForPDBData(
auto mangled_cstr = mangled.empty() ? nullptr : mangled.c_str();
bool is_constant;
- DWARFExpression location = ConvertPDBLocationToDWARFExpression(
- GetObjectFile()->GetModule(), pdb_data, ranges, is_constant);
+ ModuleSP module_sp = GetObjectFile()->GetModule();
+ DWARFExpressionList location(module_sp,
+ ConvertPDBLocationToDWARFExpression(
+ module_sp, pdb_data, ranges, is_constant),
+ nullptr);
var_sp = std::make_shared<Variable>(
var_uid, var_name.c_str(), mangled_cstr, type_sp, scope, context_scope,
diff --git a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
index 6c386f6a83fa..91eafdaa11bc 100644
--- a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.cpp
@@ -32,13 +32,12 @@ Status CommandObjectThreadTraceStartIntelPT::CommandOptions::SetOptionValue(
switch (short_option) {
case 's': {
- int64_t ipt_trace_size;
- if (option_arg.empty() || option_arg.getAsInteger(0, ipt_trace_size) ||
- ipt_trace_size < 0)
- error.SetErrorStringWithFormat("invalid integer value for option '%s'",
- option_arg.str().c_str());
+ if (Optional<uint64_t> bytes =
+ ParsingUtils::ParseUserFriendlySizeExpression(option_arg))
+ m_ipt_trace_size = *bytes;
else
- m_ipt_trace_size = ipt_trace_size;
+ error.SetErrorStringWithFormat("invalid bytes expression for '%s'",
+ option_arg.str().c_str());
break;
}
case 't': {
@@ -98,24 +97,21 @@ Status CommandObjectProcessTraceStartIntelPT::CommandOptions::SetOptionValue(
switch (short_option) {
case 's': {
- int64_t ipt_trace_size;
- if (option_arg.empty() || option_arg.getAsInteger(0, ipt_trace_size) ||
- ipt_trace_size < 0)
- error.SetErrorStringWithFormat("invalid integer value for option '%s'",
- option_arg.str().c_str());
+ if (Optional<uint64_t> bytes =
+ ParsingUtils::ParseUserFriendlySizeExpression(option_arg))
+ m_ipt_trace_size = *bytes;
else
- m_ipt_trace_size = ipt_trace_size;
+ error.SetErrorStringWithFormat("invalid bytes expression for '%s'",
+ option_arg.str().c_str());
break;
}
case 'l': {
- int64_t process_buffer_size_limit;
- if (option_arg.empty() ||
- option_arg.getAsInteger(0, process_buffer_size_limit) ||
- process_buffer_size_limit < 0)
- error.SetErrorStringWithFormat("invalid integer value for option '%s'",
- option_arg.str().c_str());
+ if (Optional<uint64_t> bytes =
+ ParsingUtils::ParseUserFriendlySizeExpression(option_arg))
+ m_process_buffer_size_limit = *bytes;
else
- m_process_buffer_size_limit = process_buffer_size_limit;
+ error.SetErrorStringWithFormat("invalid bytes expression for '%s'",
+ option_arg.str().c_str());
break;
}
case 't': {
@@ -126,6 +122,10 @@ Status CommandObjectProcessTraceStartIntelPT::CommandOptions::SetOptionValue(
m_per_cpu_tracing = true;
break;
}
+ case 'd': {
+ m_disable_cgroup_filtering = true;
+ break;
+ }
case 'p': {
int64_t psb_period;
if (option_arg.empty() || option_arg.getAsInteger(0, psb_period) ||
@@ -149,6 +149,7 @@ void CommandObjectProcessTraceStartIntelPT::CommandOptions::
m_enable_tsc = kDefaultEnableTscValue;
m_psb_period = kDefaultPsbPeriod;
m_per_cpu_tracing = kDefaultPerCpuTracing;
+ m_disable_cgroup_filtering = kDefaultDisableCgroupFiltering;
}
llvm::ArrayRef<OptionDefinition>
@@ -158,13 +159,55 @@ CommandObjectProcessTraceStartIntelPT::CommandOptions::GetDefinitions() {
bool CommandObjectProcessTraceStartIntelPT::DoExecute(
Args &command, CommandReturnObject &result) {
- if (Error err = m_trace.Start(m_options.m_ipt_trace_size,
- m_options.m_process_buffer_size_limit,
- m_options.m_enable_tsc, m_options.m_psb_period,
- m_options.m_per_cpu_tracing))
+ if (Error err = m_trace.Start(
+ m_options.m_ipt_trace_size, m_options.m_process_buffer_size_limit,
+ m_options.m_enable_tsc, m_options.m_psb_period,
+ m_options.m_per_cpu_tracing, m_options.m_disable_cgroup_filtering))
result.SetError(Status(std::move(err)));
else
result.SetStatus(eReturnStatusSuccessFinishResult);
return result.Succeeded();
}
+
+Optional<uint64_t>
+ParsingUtils::ParseUserFriendlySizeExpression(llvm::StringRef size_expression) {
+ if (size_expression.empty()) {
+ return llvm::None;
+ }
+ const uint64_t kBytesMultiplier = 1;
+ const uint64_t kKibiBytesMultiplier = 1024;
+ const uint64_t kMebiBytesMultiplier = 1024 * 1024;
+
+ DenseMap<StringRef, uint64_t> multipliers = {
+ {"mib", kMebiBytesMultiplier}, {"mb", kMebiBytesMultiplier},
+ {"m", kMebiBytesMultiplier}, {"kib", kKibiBytesMultiplier},
+ {"kb", kKibiBytesMultiplier}, {"k", kKibiBytesMultiplier},
+ {"b", kBytesMultiplier}, {"", kBytesMultiplier}};
+
+ const auto non_digit_index = size_expression.find_first_not_of("0123456789");
+ if (non_digit_index == 0) { // expression starts from from non-digit char.
+ return llvm::None;
+ }
+
+ const llvm::StringRef number_part =
+ non_digit_index == llvm::StringRef::npos
+ ? size_expression
+ : size_expression.substr(0, non_digit_index);
+ uint64_t parsed_number;
+ if (number_part.getAsInteger(10, parsed_number)) {
+ return llvm::None;
+ }
+
+ if (non_digit_index != llvm::StringRef::npos) { // if expression has units.
+ const auto multiplier = size_expression.substr(non_digit_index).lower();
+
+ auto it = multipliers.find(multiplier);
+ if (it == multipliers.end())
+ return llvm::None;
+
+ return parsed_number * it->second;
+ } else {
+ return parsed_number;
+ }
+}
diff --git a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
index b5d6a0f24043..083184e4817c 100644
--- a/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/CommandObjectTraceStartIntelPT.h
@@ -79,6 +79,7 @@ public:
bool m_enable_tsc;
llvm::Optional<uint64_t> m_psb_period;
bool m_per_cpu_tracing;
+ bool m_disable_cgroup_filtering;
};
CommandObjectProcessTraceStartIntelPT(TraceIntelPT &trace,
@@ -109,6 +110,23 @@ protected:
CommandOptions m_options;
};
+namespace ParsingUtils {
+/// Convert an integral size expression like 12KiB or 4MB into bytes. The units
+/// are taken loosely to help users input sizes into LLDB, e.g. KiB and KB are
+/// considered the same (2^20 bytes) for simplicity.
+///
+/// \param[in] size_expression
+/// String expression which is an integral number plus a unit that can be
+/// lower or upper case. Supported units: K, KB and KiB for 2^10 bytes; M,
+/// MB and MiB for 2^20 bytes; and B for bytes. A single integral number is
+/// considered bytes.
+/// \return
+/// The converted number of bytes or \a llvm::None if the expression is
+/// invalid.
+llvm::Optional<uint64_t>
+ParseUserFriendlySizeExpression(llvm::StringRef size_expression);
+} // namespace ParsingUtils
+
} // namespace trace_intel_pt
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
index 578828ff1633..0859c5a20b7e 100644
--- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
@@ -63,11 +63,28 @@ DecodedThread::CreateNewTraceItem(lldb::TraceItemKind kind) {
void DecodedThread::NotifyTsc(uint64_t tsc) {
if (!m_last_tsc || *m_last_tsc != tsc) {
- m_instruction_timestamps.emplace(m_item_kinds.size(), tsc);
+ m_timestamps.emplace(m_item_kinds.size(), tsc);
m_last_tsc = tsc;
}
}
+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_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);
+ if (it == m_cpus.begin())
+ return None;
+ return prev(it)->second;
+}
+
void DecodedThread::AppendEvent(lldb::TraceEvent event) {
CreateNewTraceItem(lldb::eTraceItemKindEvent).event = event;
m_events_stats.RecordEvent(event);
@@ -136,8 +153,8 @@ Optional<DecodedThread::TscRange> DecodedThread::CalculateTscRange(
return candidate_range;
}
// Now we do a more expensive lookup
- auto it = m_instruction_timestamps.upper_bound(insn_index);
- if (it == m_instruction_timestamps.begin())
+ auto it = m_timestamps.upper_bound(insn_index);
+ if (it == m_timestamps.begin())
return None;
return TscRange(--it, *this);
@@ -160,7 +177,8 @@ lldb::TraceCursorUP DecodedThread::CreateNewCursor() {
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_instruction_timestamps.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,
@@ -168,7 +186,7 @@ DecodedThread::TscRange::TscRange(std::map<size_t, uint64_t>::const_iterator it,
: m_it(it), m_decoded_thread(&decoded_thread) {
auto next_it = m_it;
++next_it;
- m_end_index = (next_it == m_decoded_thread->m_instruction_timestamps.end())
+ m_end_index = (next_it == m_decoded_thread->m_timestamps.end())
? std::numeric_limits<uint64_t>::max()
: next_it->first - 1;
}
@@ -191,13 +209,13 @@ bool DecodedThread::TscRange::InRange(size_t insn_index) const {
Optional<DecodedThread::TscRange> DecodedThread::TscRange::Next() const {
auto next_it = m_it;
++next_it;
- if (next_it == m_decoded_thread->m_instruction_timestamps.end())
+ 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_instruction_timestamps.begin())
+ if (m_it == m_decoded_thread->m_timestamps.begin())
return None;
auto prev_it = m_it;
--prev_it;
diff --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
index b17e927fafe4..bd1a90aaf250 100644
--- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
+++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
@@ -168,6 +168,15 @@ public:
/// The underlying event type for the given trace item index.
lldb::TraceEvent GetEventByIndex(int item_index) const;
+ /// Get the most recent CPU id before or at the given trace item index.
+ ///
+ /// \param[in] item_index
+ /// The trace item index to compare with.
+ ///
+ /// \return
+ /// The requested cpu id, or \a llvm::None if not available.
+ llvm::Optional<lldb::cpu_id_t> GetCPUByIndex(uint64_t item_index) const;
+
/// \return
/// The load address of the instruction at the given index.
lldb::addr_t GetInstructionLoadAddress(size_t item_index) const;
@@ -204,8 +213,13 @@ public:
lldb::ThreadSP GetThread();
/// 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);
+ /// Notify this object that a CPU has been seen.
+ /// If this a new CPU, an event will be created.
+ void NotifyCPU(lldb::cpu_id_t cpu_id);
+
/// Append a decoding error.
void AppendError(const IntelPTError &error);
@@ -254,10 +268,17 @@ private:
/// 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_instruction_timestamps;
+ std::map<uint64_t, uint64_t> m_timestamps;
/// This is the chronologically last TSC that has been added.
llvm::Optional<uint64_t> m_last_tsc = 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
+ // cpu is seen.
+ std::map<uint64_t, lldb::cpu_id_t> m_cpus;
+ /// This is the chronologically last CPU ID.
+ llvm::Optional<uint64_t> m_last_cpu = llvm::None;
+
/// Statistics of all tracing events.
EventsStats m_events_stats;
/// Statistics of libipt errors when decoding TSCs.
diff --git a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
index dd34467e38b5..a98337a4e058 100644
--- a/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/LibiptDecoder.cpp
@@ -285,6 +285,8 @@ 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;
// If we haven't seen a PSB yet, then it's fine not to show errors
if (has_seen_psbs) {
diff --git a/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp
index 6b4251a0fcd9..0c468cf7852f 100644
--- a/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.cpp
@@ -16,8 +16,13 @@ using namespace llvm;
/// non-linux platforms.
/// \{
#define PERF_RECORD_MISC_SWITCH_OUT (1 << 13)
-#define PERF_RECORD_MAX 19
+
+#define PERF_RECORD_LOST 2
+#define PERF_RECORD_THROTTLE 5
+#define PERF_RECORD_UNTHROTTLE 6
+#define PERF_RECORD_LOST_SAMPLES 13
#define PERF_RECORD_SWITCH_CPU_WIDE 15
+#define PERF_RECORD_MAX 19
struct perf_event_header {
uint32_t type;
@@ -54,6 +59,11 @@ struct perf_event_header {
bool IsContextSwitchRecord() const {
return type == PERF_RECORD_SWITCH_CPU_WIDE;
}
+
+ bool IsErrorRecord() const {
+ return type == PERF_RECORD_LOST || type == PERF_RECORD_THROTTLE ||
+ type == PERF_RECORD_UNTHROTTLE || type == PERF_RECORD_LOST_SAMPLES;
+ }
};
/// \}
@@ -286,3 +296,36 @@ lldb_private::trace_intel_pt::DecodePerfContextSwitchTrace(
return executions;
}
+
+Expected<std::vector<uint8_t>>
+lldb_private::trace_intel_pt::FilterProcessesFromContextSwitchTrace(
+ llvm::ArrayRef<uint8_t> data, const std::set<lldb::pid_t> &pids) {
+ size_t offset = 0;
+ std::vector<uint8_t> out_data;
+
+ while (offset < data.size()) {
+ const perf_event_header &perf_record =
+ *reinterpret_cast<const perf_event_header *>(data.data() + offset);
+ if (Error err = perf_record.SanityCheck())
+ return std::move(err);
+ bool should_copy = false;
+ if (perf_record.IsContextSwitchRecord()) {
+ const PerfContextSwitchRecord &context_switch_record =
+ *reinterpret_cast<const PerfContextSwitchRecord *>(data.data() +
+ offset);
+ if (pids.count(context_switch_record.pid))
+ should_copy = true;
+ } else if (perf_record.IsErrorRecord()) {
+ should_copy = true;
+ }
+
+ if (should_copy) {
+ for (size_t i = 0; i < perf_record.size; i++) {
+ out_data.push_back(data[offset + i]);
+ }
+ }
+
+ offset += perf_record.size;
+ }
+ return out_data;
+}
diff --git a/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h b/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h
index 721aa1d77481..a16a437e1888 100644
--- a/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h
+++ b/lldb/source/Plugins/Trace/intel-pt/PerfContextSwitchDecoder.h
@@ -14,6 +14,7 @@
#include "llvm/Support/Error.h"
+#include <set>
#include <vector>
namespace lldb_private {
@@ -139,6 +140,10 @@ DecodePerfContextSwitchTrace(llvm::ArrayRef<uint8_t> data,
lldb::cpu_id_t cpu_id,
const LinuxPerfZeroTscConversion &tsc_conversion);
+llvm::Expected<std::vector<uint8_t>>
+FilterProcessesFromContextSwitchTrace(llvm::ArrayRef<uint8_t> data,
+ const std::set<lldb::pid_t> &pids);
+
} // namespace trace_intel_pt
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Trace/intel-pt/TaskTimer.h b/lldb/source/Plugins/Trace/intel-pt/TaskTimer.h
index 92b563257437..2b85ed30334f 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TaskTimer.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TaskTimer.h
@@ -35,9 +35,9 @@ public:
///
/// \return
/// The return value of the task.
- template <class R> R TimeTask(llvm::StringRef name, std::function<R()> task) {
+ template <typename C> auto TimeTask(llvm::StringRef name, C task) {
auto start = std::chrono::steady_clock::now();
- R result = task();
+ auto result = task();
auto end = std::chrono::steady_clock::now();
std::chrono::milliseconds duration =
std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
diff --git a/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
index 8b90afb219af..d3ac61f7e658 100644
--- a/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/ThreadDecoder.cpp
@@ -35,9 +35,8 @@ Expected<DecodedThreadSP> ThreadDecoder::Decode() {
}
llvm::Expected<DecodedThreadSP> ThreadDecoder::DoDecode() {
- return m_trace.GetTimer()
- .ForThread(m_thread_sp->GetID())
- .TimeTask<Expected<DecodedThreadSP>>(
+ return m_trace.GetThreadTimer(m_thread_sp->GetID())
+ .TimeTask(
"Decoding instructions", [&]() -> Expected<DecodedThreadSP> {
DecodedThreadSP decoded_thread_sp =
std::make_shared<DecodedThread>(m_thread_sp);
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
index da91ba7c13d8..185c02b6bcd9 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
@@ -84,6 +84,10 @@ TraceCursorIntelPT::GetCounter(lldb::TraceCounter counter_type) const {
}
}
+Optional<lldb::cpu_id_t> TraceCursorIntelPT::GetCPU() const {
+ return m_decoded_thread_sp->GetCPUByIndex(m_pos);
+}
+
lldb::TraceEvent TraceCursorIntelPT::GetEventType() const {
return m_decoded_thread_sp->GetEventByIndex(m_pos);
}
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
index c90431de3bbc..2e0f67e67dfc 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
@@ -34,6 +34,8 @@ public:
lldb::TraceEvent GetEventType() const override;
+ llvm::Optional<lldb::cpu_id_t> GetCPU() const override;
+
lldb::TraceItemKind GetItemKind() const override;
bool GoToId(lldb::user_id_t id) override;
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
index fc7a103fbe15..57433ffb14cb 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -55,9 +55,9 @@ StringRef TraceIntelPT::GetSchema() {
void TraceIntelPT::Dump(Stream *s) const {}
-llvm::Error TraceIntelPT::SaveLiveTraceToDisk(FileSpec directory) {
+Expected<FileSpec> TraceIntelPT::SaveToDisk(FileSpec directory, bool compact) {
RefreshLiveProcessState();
- return TraceIntelPTBundleSaver().SaveToDisk(*this, directory);
+ return TraceIntelPTBundleSaver().SaveToDisk(*this, directory, compact);
}
Expected<TraceSP> TraceIntelPT::CreateInstanceForTraceBundle(
@@ -146,10 +146,16 @@ TraceIntelPT::CreateNewCursor(Thread &thread) {
return decoded_thread.takeError();
}
-void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose) {
+void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose,
+ bool json) {
Storage &storage = GetUpdatedStorage();
lldb::tid_t tid = thread.GetID();
+ if (json) {
+ DumpTraceInfoAsJson(thread, s, verbose);
+ return;
+ }
+
s.Format("\nthread #{0}: tid = {1}", thread.GetIndexID(), thread.GetID());
if (!IsTraced(tid)) {
s << ", not traced\n";
@@ -172,12 +178,14 @@ void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose) {
}
Optional<uint64_t> raw_size = *raw_size_or_error;
+ s.Format("\n Trace technology: {0}\n", GetPluginName());
+
/// Instruction stats
{
uint64_t items_count = decoded_thread_sp->GetItemsCount();
uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();
- s.Format(" Total number of trace items: {0}\n", items_count);
+ s.Format("\n Total number of trace items: {0}\n", items_count);
s << "\n Memory usage:\n";
if (raw_size)
@@ -199,10 +207,10 @@ void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose) {
std::chrono::milliseconds duration) {
s.Format(" {0}: {1:2}s\n", name, duration.count() / 1000.0);
};
- GetTimer().ForThread(tid).ForEachTimedTask(print_duration);
+ GetThreadTimer(tid).ForEachTimedTask(print_duration);
s << "\n Timing for global tasks:\n";
- GetTimer().ForGlobal().ForEachTimedTask(print_duration);
+ GetGlobalTimer().ForEachTimedTask(print_duration);
}
// Instruction events stats
@@ -226,6 +234,12 @@ void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose) {
s.Format(
" Number of continuous executions for this thread: {0}\n",
storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));
+ s.Format(" Total number of PSB blocks found: {0}\n",
+ storage.multicpu_decoder->GetTotalPSBBlocksCount());
+ s.Format(" Number of PSB blocks for this thread: {0}\n",
+ storage.multicpu_decoder->GePSBBlocksCountForThread(tid));
+ s.Format(" Total number of unattributed PSB blocks found: {0}\n",
+ storage.multicpu_decoder->GetUnattributedPSBBlocksCount());
}
// Errors
@@ -243,6 +257,117 @@ void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose) {
}
}
+void TraceIntelPT::DumpTraceInfoAsJson(Thread &thread, Stream &s,
+ bool verbose) {
+ Storage &storage = GetUpdatedStorage();
+
+ lldb::tid_t tid = thread.GetID();
+ json::OStream json_str(s.AsRawOstream(), 2);
+ if (!IsTraced(tid)) {
+ s << "error: thread not traced\n";
+ return;
+ }
+
+ Expected<Optional<uint64_t>> raw_size_or_error = GetRawTraceSize(thread);
+ if (!raw_size_or_error) {
+ s << "error: " << toString(raw_size_or_error.takeError()) << "\n";
+ return;
+ }
+
+ Expected<DecodedThreadSP> decoded_thread_sp_or_err = Decode(thread);
+ if (!decoded_thread_sp_or_err) {
+ s << "error: " << toString(decoded_thread_sp_or_err.takeError()) << "\n";
+ return;
+ }
+ DecodedThreadSP &decoded_thread_sp = *decoded_thread_sp_or_err;
+
+ json_str.object([&] {
+ json_str.attribute("traceTechnology", "intel-pt");
+ json_str.attributeObject("threadStats", [&] {
+ json_str.attribute("tid", tid);
+
+ uint64_t insn_len = decoded_thread_sp->GetItemsCount();
+ json_str.attribute("traceItemsCount", insn_len);
+
+ // Instruction stats
+ uint64_t mem_used = decoded_thread_sp->CalculateApproximateMemoryUsage();
+ json_str.attributeObject("memoryUsage", [&] {
+ json_str.attribute("totalInBytes", std::to_string(mem_used));
+ Optional<double> avg;
+ if (insn_len != 0)
+ avg = double(mem_used) / insn_len;
+ json_str.attribute("avgPerItemInBytes", avg);
+ });
+
+ // Timing
+ json_str.attributeObject("timingInSeconds", [&] {
+ GetTimer().ForThread(tid).ForEachTimedTask(
+ [&](const std::string &name, std::chrono::milliseconds duration) {
+ json_str.attribute(name, duration.count() / 1000.0);
+ });
+ });
+
+ // Instruction events stats
+ const DecodedThread::EventsStats &events_stats =
+ decoded_thread_sp->GetEventsStats();
+ json_str.attributeObject("events", [&] {
+ json_str.attribute("totalCount", events_stats.total_count);
+ json_str.attributeObject("individualCounts", [&] {
+ for (const auto &event_to_count : events_stats.events_counts) {
+ json_str.attribute(
+ TraceCursor::EventKindToString(event_to_count.first),
+ event_to_count.second);
+ }
+ });
+ });
+
+ if (storage.multicpu_decoder) {
+ json_str.attribute(
+ "continuousExecutions",
+ storage.multicpu_decoder->GetNumContinuousExecutionsForThread(tid));
+ json_str.attribute(
+ "PSBBlocks",
+ storage.multicpu_decoder->GePSBBlocksCountForThread(tid));
+ }
+
+ // Errors
+ const DecodedThread::LibiptErrorsStats &tsc_errors_stats =
+ decoded_thread_sp->GetTscErrorsStats();
+ json_str.attributeObject("errorItems", [&] {
+ json_str.attribute("total", tsc_errors_stats.total_count);
+ json_str.attributeObject("individualErrors", [&] {
+ for (const auto &error_message_to_count :
+ tsc_errors_stats.libipt_errors_counts) {
+ json_str.attribute(error_message_to_count.first,
+ error_message_to_count.second);
+ }
+ });
+ });
+ });
+ json_str.attributeObject("globalStats", [&] {
+ json_str.attributeObject("timingInSeconds", [&] {
+ GetTimer().ForGlobal().ForEachTimedTask(
+ [&](const std::string &name, std::chrono::milliseconds duration) {
+ json_str.attribute(name, duration.count() / 1000.0);
+ });
+ });
+ if (storage.multicpu_decoder) {
+ json_str.attribute(
+ "totalUnattributedPSBBlocks",
+ storage.multicpu_decoder->GetUnattributedPSBBlocksCount());
+ json_str.attribute(
+ "totalCountinuosExecutions",
+ storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
+ json_str.attribute("totalPSBBlocks",
+ storage.multicpu_decoder->GetTotalPSBBlocksCount());
+ json_str.attribute(
+ "totalContinuousExecutions",
+ storage.multicpu_decoder->GetTotalContinuousExecutionsCount());
+ }
+ });
+ });
+}
+
llvm::Expected<Optional<uint64_t>>
TraceIntelPT::GetRawTraceSize(Thread &thread) {
if (GetUpdatedStorage().multicpu_decoder)
@@ -408,17 +533,22 @@ const char *TraceIntelPT::GetStartConfigurationHelp() {
[process tracing only]
- int processBufferSizeLimit (defaults to {4} MiB):
+ [process tracing only]
+
+ - boolean disableCgroupFiltering (default to {5}):
[process tracing only])",
kDefaultIptTraceSize, kDefaultEnableTscValue,
kDefaultPsbPeriod, kDefaultPerCpuTracing,
- kDefaultProcessBufferSizeLimit / 1024 / 1024));
+ kDefaultProcessBufferSizeLimit / 1024 / 1024,
+ kDefaultDisableCgroupFiltering));
}
return message->c_str();
}
Error TraceIntelPT::Start(uint64_t ipt_trace_size,
uint64_t total_buffer_size_limit, bool enable_tsc,
- Optional<uint64_t> psb_period, bool per_cpu_tracing) {
+ Optional<uint64_t> psb_period, bool per_cpu_tracing,
+ bool disable_cgroup_filtering) {
TraceIntelPTStartRequest request;
request.ipt_trace_size = ipt_trace_size;
request.process_buffer_size_limit = total_buffer_size_limit;
@@ -426,6 +556,7 @@ Error TraceIntelPT::Start(uint64_t ipt_trace_size,
request.psb_period = psb_period;
request.type = GetPluginName().str();
request.per_cpu_tracing = per_cpu_tracing;
+ request.disable_cgroup_filtering = disable_cgroup_filtering;
return Trace::Start(toJSON(request));
}
@@ -435,6 +566,7 @@ Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) {
bool enable_tsc = kDefaultEnableTscValue;
Optional<uint64_t> psb_period = kDefaultPsbPeriod;
bool per_cpu_tracing = kDefaultPerCpuTracing;
+ bool disable_cgroup_filtering = kDefaultDisableCgroupFiltering;
if (configuration) {
if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
@@ -444,6 +576,8 @@ Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) {
dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
dict->GetValueForKeyAsBoolean("perCpuTracing", per_cpu_tracing);
+ dict->GetValueForKeyAsBoolean("disableCgroupFiltering",
+ disable_cgroup_filtering);
} else {
return createStringError(inconvertibleErrorCode(),
"configuration object is not a dictionary");
@@ -451,7 +585,7 @@ Error TraceIntelPT::Start(StructuredData::ObjectSP configuration) {
}
return Start(ipt_trace_size, process_buffer_size_limit, enable_tsc,
- psb_period, per_cpu_tracing);
+ psb_period, per_cpu_tracing, disable_cgroup_filtering);
}
llvm::Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
@@ -476,7 +610,20 @@ Error TraceIntelPT::Start(llvm::ArrayRef<lldb::tid_t> tids,
if (configuration) {
if (StructuredData::Dictionary *dict = configuration->GetAsDictionary()) {
- dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);
+ llvm::StringRef ipt_trace_size_not_parsed;
+ if (dict->GetValueForKeyAsString("iptTraceSize",
+ ipt_trace_size_not_parsed)) {
+ if (Optional<uint64_t> bytes =
+ ParsingUtils::ParseUserFriendlySizeExpression(
+ ipt_trace_size_not_parsed))
+ ipt_trace_size = *bytes;
+ else
+ return createStringError(inconvertibleErrorCode(),
+ "iptTraceSize is wrong bytes expression");
+ } else {
+ dict->GetValueForKeyAsInteger("iptTraceSize", ipt_trace_size);
+ }
+
dict->GetValueForKeyAsBoolean("enableTsc", enable_tsc);
dict->GetValueForKeyAsInteger("psbPeriod", psb_period);
} else {
@@ -494,3 +641,11 @@ Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid,
}
TaskTimer &TraceIntelPT::GetTimer() { return GetUpdatedStorage().task_timer; }
+
+ScopedTaskTimer &TraceIntelPT::GetThreadTimer(lldb::tid_t tid) {
+ return GetTimer().ForThread(tid);
+}
+
+ScopedTaskTimer &TraceIntelPT::GetGlobalTimer() {
+ return GetTimer().ForGlobal();
+}
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
index 09ecbe7da61a..d3e58374867d 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
@@ -25,7 +25,8 @@ class TraceIntelPT : public Trace {
public:
void Dump(Stream *s) const override;
- llvm::Error SaveLiveTraceToDisk(FileSpec directory) override;
+ llvm::Expected<FileSpec> SaveToDisk(FileSpec directory,
+ bool compact) override;
~TraceIntelPT() override = default;
@@ -72,7 +73,8 @@ public:
llvm::Expected<lldb::TraceCursorUP> CreateNewCursor(Thread &thread) override;
- void DumpTraceInfo(Thread &thread, Stream &s, bool verbose) override;
+ void DumpTraceInfo(Thread &thread, Stream &s, bool verbose,
+ bool json) override;
llvm::Expected<llvm::Optional<uint64_t>> GetRawTraceSize(Thread &thread);
@@ -104,12 +106,16 @@ public:
/// This value defines whether to have an intel pt trace buffer per thread
/// or per cpu core.
///
+ /// \param[in] disable_cgroup_filtering
+ /// Disable the cgroup filtering that is automatically applied when doing
+ /// per cpu tracing.
+ ///
/// \return
/// \a llvm::Error::success if the operation was successful, or
/// \a llvm::Error otherwise.
llvm::Error Start(uint64_t ipt_trace_size, uint64_t total_buffer_size_limit,
bool enable_tsc, llvm::Optional<uint64_t> psb_period,
- bool m_per_cpu_tracing);
+ bool m_per_cpu_tracing, bool disable_cgroup_filtering);
/// \copydoc Trace::Start
llvm::Error Start(StructuredData::ObjectSP configuration =
@@ -157,6 +163,14 @@ public:
/// The timer object for this trace.
TaskTimer &GetTimer();
+ /// \return
+ /// The ScopedTaskTimer object for the given thread in this trace.
+ ScopedTaskTimer &GetThreadTimer(lldb::tid_t tid);
+
+ /// \return
+ /// The global copedTaskTimer object for this trace.
+ ScopedTaskTimer &GetGlobalTimer();
+
TraceIntelPTSP GetSharedPtr();
private:
@@ -206,6 +220,9 @@ private:
/// returned if the decoder couldn't be properly set up.
llvm::Expected<DecodedThreadSP> Decode(Thread &thread);
+ // Dump out trace info in JSON format
+ void DumpTraceInfoAsJson(Thread &thread, Stream &s, bool verbose);
+
/// We package all the data that can change upon process stops to make sure
/// this contract is very visible.
/// This variable should only be accessed directly by constructores or live
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.cpp
index b2ebaee732b8..8be70dc2139b 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.cpp
@@ -7,8 +7,11 @@
//===----------------------------------------------------------------------===//
#include "TraceIntelPTBundleSaver.h"
+
+#include "PerfContextSwitchDecoder.h"
#include "TraceIntelPT.h"
#include "TraceIntelPTJSONStructs.h"
+
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Target/Process.h"
@@ -30,6 +33,13 @@ using namespace lldb_private;
using namespace lldb_private::trace_intel_pt;
using namespace llvm;
+/// Strip the \p directory component from the given \p path. It assumes that \p
+/// directory is a prefix of \p path.
+static std::string GetRelativePath(const FileSpec &directory,
+ const FileSpec &path) {
+ return path.GetPath().substr(directory.GetPath().size() + 1);
+}
+
/// Write a stream of bytes from \p data to the given output file.
/// It creates or overwrites the output file, but not append.
static llvm::Error WriteBytesToDisk(FileSpec &output_file,
@@ -57,11 +67,11 @@ static llvm::Error WriteBytesToDisk(FileSpec &output_file,
/// The directory where the JSON file will be saved.
///
/// \return
-/// \a llvm::Success if the operation was successful, or an \a llvm::Error
-/// otherwise.
-static llvm::Error
+/// A \a FileSpec pointing to the bundle description file, or an \a
+/// llvm::Error otherwise.
+static Expected<FileSpec>
SaveTraceBundleDescription(const llvm::json::Value &trace_bundle_description,
- const FileSpec &directory) {
+ const FileSpec &directory) {
FileSpec trace_path = directory;
trace_path.AppendPathComponent("trace.json");
std::ofstream os(trace_path.GetPath());
@@ -71,7 +81,7 @@ SaveTraceBundleDescription(const llvm::json::Value &trace_bundle_description,
return createStringError(inconvertibleErrorCode(),
formatv("couldn't write to the file {0}",
trace_path.GetPath().c_str()));
- return Error::success();
+ return trace_path;
}
/// Build the threads sub-section of the trace bundle description file.
@@ -106,7 +116,7 @@ BuildThreadsSection(Process &process, FileSpec directory) {
if (trace_sp->GetTracedCpus().empty()) {
FileSpec output_file = threads_dir;
output_file.AppendPathComponent(std::to_string(tid) + ".intelpt_trace");
- json_thread.ipt_trace = output_file.GetPath();
+ json_thread.ipt_trace = GetRelativePath(directory, output_file);
llvm::Error err = process.GetTarget().GetTrace()->OnThreadBinaryDataRead(
tid, IntelPTDataKinds::kIptTrace,
@@ -122,8 +132,68 @@ BuildThreadsSection(Process &process, FileSpec directory) {
return json_threads;
}
+/// \return
+/// an \a llvm::Error in case of failures, \a None if the trace is not written
+/// to disk because the trace is empty and the \p compact flag is present, or
+/// the FileSpec of the trace file on disk.
+static Expected<Optional<FileSpec>>
+WriteContextSwitchTrace(TraceIntelPT &trace_ipt, lldb::cpu_id_t cpu_id,
+ const FileSpec &cpus_dir, bool compact) {
+ FileSpec output_context_switch_trace = cpus_dir;
+ output_context_switch_trace.AppendPathComponent(std::to_string(cpu_id) +
+ ".perf_context_switch_trace");
+
+ bool should_skip = false;
+
+ Error err = trace_ipt.OnCpuBinaryDataRead(
+ cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace,
+ [&](llvm::ArrayRef<uint8_t> data) -> llvm::Error {
+ if (!compact)
+ return WriteBytesToDisk(output_context_switch_trace, data);
+
+ std::set<lldb::pid_t> pids;
+ for (Process *process : trace_ipt.GetAllProcesses())
+ pids.insert(process->GetID());
+
+ Expected<std::vector<uint8_t>> compact_context_switch_trace =
+ FilterProcessesFromContextSwitchTrace(data, pids);
+ if (!compact_context_switch_trace)
+ return compact_context_switch_trace.takeError();
+
+ if (compact_context_switch_trace->empty()) {
+ should_skip = true;
+ return Error::success();
+ }
+
+ return WriteBytesToDisk(output_context_switch_trace,
+ *compact_context_switch_trace);
+ });
+ if (err)
+ return std::move(err);
+
+ if (should_skip)
+ return None;
+ return output_context_switch_trace;
+}
+
+static Expected<FileSpec> WriteIntelPTTrace(TraceIntelPT &trace_ipt,
+ lldb::cpu_id_t cpu_id,
+ const FileSpec &cpus_dir) {
+ FileSpec output_trace = cpus_dir;
+ output_trace.AppendPathComponent(std::to_string(cpu_id) + ".intelpt_trace");
+
+ Error err = trace_ipt.OnCpuBinaryDataRead(
+ cpu_id, IntelPTDataKinds::kIptTrace,
+ [&](llvm::ArrayRef<uint8_t> data) -> llvm::Error {
+ return WriteBytesToDisk(output_trace, data);
+ });
+ if (err)
+ return std::move(err);
+ return output_trace;
+}
+
static llvm::Expected<llvm::Optional<std::vector<JSONCpu>>>
-BuildCpusSection(TraceIntelPT &trace_ipt, FileSpec directory) {
+BuildCpusSection(TraceIntelPT &trace_ipt, FileSpec directory, bool compact) {
if (trace_ipt.GetTracedCpus().empty())
return None;
@@ -135,36 +205,21 @@ BuildCpusSection(TraceIntelPT &trace_ipt, FileSpec directory) {
for (lldb::cpu_id_t cpu_id : trace_ipt.GetTracedCpus()) {
JSONCpu json_cpu;
json_cpu.id = cpu_id;
+ Expected<Optional<FileSpec>> context_switch_trace_path =
+ WriteContextSwitchTrace(trace_ipt, cpu_id, cpus_dir, compact);
+ if (!context_switch_trace_path)
+ return context_switch_trace_path.takeError();
+ if (!*context_switch_trace_path)
+ continue;
+ json_cpu.context_switch_trace =
+ GetRelativePath(directory, **context_switch_trace_path);
- {
- FileSpec output_trace = cpus_dir;
- output_trace.AppendPathComponent(std::to_string(cpu_id) +
- ".intelpt_trace");
- json_cpu.ipt_trace = output_trace.GetPath();
-
- llvm::Error err = trace_ipt.OnCpuBinaryDataRead(
- cpu_id, IntelPTDataKinds::kIptTrace,
- [&](llvm::ArrayRef<uint8_t> data) -> llvm::Error {
- return WriteBytesToDisk(output_trace, data);
- });
- if (err)
- return std::move(err);
- }
-
- {
- FileSpec output_context_switch_trace = cpus_dir;
- output_context_switch_trace.AppendPathComponent(
- std::to_string(cpu_id) + ".perf_context_switch_trace");
- json_cpu.context_switch_trace = output_context_switch_trace.GetPath();
+ if (Expected<FileSpec> ipt_trace_path =
+ WriteIntelPTTrace(trace_ipt, cpu_id, cpus_dir))
+ json_cpu.ipt_trace = GetRelativePath(directory, *ipt_trace_path);
+ else
+ return ipt_trace_path.takeError();
- llvm::Error err = trace_ipt.OnCpuBinaryDataRead(
- cpu_id, IntelPTDataKinds::kPerfContextSwitchTrace,
- [&](llvm::ArrayRef<uint8_t> data) -> llvm::Error {
- return WriteBytesToDisk(output_context_switch_trace, data);
- });
- if (err)
- return std::move(err);
- }
json_cpus.push_back(std::move(json_cpu));
}
return json_cpus;
@@ -222,14 +277,14 @@ BuildModulesSection(Process &process, FileSpec directory) {
path_to_copy_module.AppendPathComponent(system_path);
sys::fs::create_directories(path_to_copy_module.GetDirectory().AsCString());
- if (std::error_code ec = llvm::sys::fs::copy_file(
- system_path, path_to_copy_module.GetPath()))
+ if (std::error_code ec =
+ llvm::sys::fs::copy_file(file, path_to_copy_module.GetPath()))
return createStringError(
inconvertibleErrorCode(),
formatv("couldn't write to the file. {0}", ec.message()));
json_modules.push_back(
- JSONModule{system_path, path_to_copy_module.GetPath(),
+ JSONModule{system_path, GetRelativePath(directory, path_to_copy_module),
JSONUINT64{load_addr}, module_sp->GetUUID().GetAsString()});
}
return json_modules;
@@ -280,8 +335,9 @@ BuildProcessesSection(TraceIntelPT &trace_ipt, const FileSpec &directory) {
return processes;
}
-Error TraceIntelPTBundleSaver::SaveToDisk(TraceIntelPT &trace_ipt,
- FileSpec directory) {
+Expected<FileSpec> TraceIntelPTBundleSaver::SaveToDisk(TraceIntelPT &trace_ipt,
+ FileSpec directory,
+ bool compact) {
if (std::error_code ec =
sys::fs::create_directories(directory.GetPath().c_str()))
return llvm::errorCodeToError(ec);
@@ -299,7 +355,7 @@ Error TraceIntelPTBundleSaver::SaveToDisk(TraceIntelPT &trace_ipt,
return json_processes.takeError();
Expected<Optional<std::vector<JSONCpu>>> json_cpus =
- BuildCpusSection(trace_ipt, directory);
+ BuildCpusSection(trace_ipt, directory, compact);
if (!json_cpus)
return json_cpus.takeError();
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.h
index c36677e1c00d..7224636f0c74 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTBundleSaver.h
@@ -31,10 +31,16 @@ public:
/// \param[in] directory
/// The directory where the trace bundle will be created.
///
+ /// \param[in] compact
+ /// Filter out information irrelevant to the traced processes in the
+ /// context switch and intel pt traces when using per-cpu mode. This
+ /// effectively reduces the size of those traces.
+ ///
/// \return
- /// \a llvm::success if the operation was successful, or an \a llvm::Error
- /// otherwise.
- llvm::Error SaveToDisk(TraceIntelPT &trace_ipt, FileSpec directory);
+ /// A \a FileSpec pointing to the bundle description file, or an \a
+ /// llvm::Error otherwise.
+ llvm::Expected<FileSpec> SaveToDisk(TraceIntelPT &trace_ipt,
+ FileSpec directory, bool compact);
};
} // namespace trace_intel_pt
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h
index 61fdb4574d54..43c86fca3425 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTConstants.h
@@ -21,6 +21,7 @@ const size_t kDefaultProcessBufferSizeLimit = 5 * 1024 * 1024; // 500MB
const bool kDefaultEnableTscValue = false;
const llvm::Optional<size_t> kDefaultPsbPeriod = llvm::None;
const bool kDefaultPerCpuTracing = false;
+const bool kDefaultDisableCgroupFiltering = false;
} // namespace trace_intel_pt
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp
index d2dbc049672c..e547032f739d 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.cpp
@@ -1,4 +1,4 @@
-//===-- TraceIntelPTMultiCpuDecoder.cpp ----0------------------------------===//
+//===-- TraceIntelPTMultiCpuDecoder.cpp -----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -39,30 +39,35 @@ Expected<DecodedThreadSP> TraceIntelPTMultiCpuDecoder::Decode(Thread &thread) {
if (Error err = CorrelateContextSwitchesAndIntelPtTraces())
return std::move(err);
- auto it = m_decoded_threads.find(thread.GetID());
- if (it != m_decoded_threads.end())
- return it->second;
-
- DecodedThreadSP decoded_thread_sp =
- std::make_shared<DecodedThread>(thread.shared_from_this());
-
TraceIntelPTSP trace_sp = GetTrace();
- Error err = trace_sp->OnAllCpusBinaryDataRead(
- IntelPTDataKinds::kIptTrace,
- [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
- auto it = m_continuous_executions_per_thread->find(thread.GetID());
- if (it != m_continuous_executions_per_thread->end())
- return DecodeSystemWideTraceForThread(*decoded_thread_sp, *trace_sp,
- buffers, it->second);
-
- return Error::success();
+ return trace_sp
+ ->GetThreadTimer(thread.GetID())
+ .TimeTask("Decoding instructions", [&]() -> Expected<DecodedThreadSP> {
+ auto it = m_decoded_threads.find(thread.GetID());
+ if (it != m_decoded_threads.end())
+ return it->second;
+
+ DecodedThreadSP decoded_thread_sp =
+ std::make_shared<DecodedThread>(thread.shared_from_this());
+
+ Error err = trace_sp->OnAllCpusBinaryDataRead(
+ IntelPTDataKinds::kIptTrace,
+ [&](const DenseMap<cpu_id_t, ArrayRef<uint8_t>> &buffers) -> Error {
+ auto it =
+ m_continuous_executions_per_thread->find(thread.GetID());
+ if (it != m_continuous_executions_per_thread->end())
+ return DecodeSystemWideTraceForThread(
+ *decoded_thread_sp, *trace_sp, buffers, it->second);
+
+ return Error::success();
+ });
+ if (err)
+ return std::move(err);
+
+ m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp);
+ return decoded_thread_sp;
});
- if (err)
- return std::move(err);
-
- m_decoded_threads.try_emplace(thread.GetID(), decoded_thread_sp);
- return decoded_thread_sp;
}
static Expected<std::vector<IntelPTThreadSubtrace>>
@@ -105,6 +110,7 @@ TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() {
if (!intel_pt_subtraces)
return intel_pt_subtraces.takeError();
+ m_total_psb_blocks += intel_pt_subtraces->size();
// We'll be iterating through the thread continuous executions and the intel
// pt subtraces sorted by time.
auto it = intel_pt_subtraces->begin();
@@ -118,7 +124,7 @@ TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() {
if (it->tsc > thread_execution.GetStartTSC()) {
execution.intelpt_subtraces.push_back(*it);
} else {
- m_unattributed_intelpt_subtraces++;
+ m_unattributed_psb_blocks++;
}
}
continuous_executions_per_thread[thread_execution.tid].push_back(
@@ -137,6 +143,8 @@ TraceIntelPTMultiCpuDecoder::DoCorrelateContextSwitchesAndIntelPtTraces() {
});
if (err)
return std::move(err);
+
+ m_unattributed_psb_blocks += intel_pt_subtraces->end() - it;
}
// We now sort the executions of each thread to have them ready for
// instruction decoding
@@ -153,7 +161,7 @@ Error TraceIntelPTMultiCpuDecoder::CorrelateContextSwitchesAndIntelPtTraces() {
if (m_continuous_executions_per_thread)
return Error::success();
- Error err = GetTrace()->GetTimer().ForGlobal().TimeTask<Error>(
+ Error err = GetTrace()->GetGlobalTimer().TimeTask(
"Context switch and Intel PT traces correlation", [&]() -> Error {
if (auto correlation = DoCorrelateContextSwitchesAndIntelPtTraces()) {
m_continuous_executions_per_thread.emplace(std::move(*correlation));
@@ -187,3 +195,24 @@ size_t TraceIntelPTMultiCpuDecoder::GetTotalContinuousExecutionsCount() const {
count += kv.second.size();
return count;
}
+
+size_t
+TraceIntelPTMultiCpuDecoder::GePSBBlocksCountForThread(lldb::tid_t tid) const {
+ if (!m_continuous_executions_per_thread)
+ return 0;
+ size_t count = 0;
+ auto it = m_continuous_executions_per_thread->find(tid);
+ if (it == m_continuous_executions_per_thread->end())
+ return 0;
+ for (const IntelPTThreadContinousExecution &execution : it->second)
+ count += execution.intelpt_subtraces.size();
+ return count;
+}
+
+size_t TraceIntelPTMultiCpuDecoder::GetUnattributedPSBBlocksCount() const {
+ return m_unattributed_psb_blocks;
+}
+
+size_t TraceIntelPTMultiCpuDecoder::GetTotalPSBBlocksCount() const {
+ return m_total_psb_blocks;
+}
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h
index 11771e018f7b..3b7926760f3c 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCpuDecoder.h
@@ -50,9 +50,22 @@ public:
size_t GetNumContinuousExecutionsForThread(lldb::tid_t tid) const;
/// \return
+ /// The number of PSB blocks for a given thread in all cores.
+ size_t GePSBBlocksCountForThread(lldb::tid_t tid) const;
+
+ /// \return
/// The total number of continuous executions found across CPUs.
size_t GetTotalContinuousExecutionsCount() const;
+ /// \return
+ /// The number of psb blocks in all cores that couldn't be matched with a
+ /// thread execution coming from context switch traces.
+ size_t GetUnattributedPSBBlocksCount() const;
+
+ /// \return
+ /// The total number of PSB blocks in all cores.
+ size_t GetTotalPSBBlocksCount() const;
+
private:
/// Traverse the context switch traces and the basic intel pt continuous
/// subtraces and produce a list of continuous executions for each process and
@@ -80,7 +93,8 @@ private:
/// This variable will be non-None if a severe error happened during the setup
/// of the decoder and we don't want decoding to be reattempted.
llvm::Optional<std::string> m_setup_error;
- uint64_t m_unattributed_intelpt_subtraces;
+ uint64_t m_unattributed_psb_blocks = 0;
+ uint64_t m_total_psb_blocks = 0;
};
} // namespace trace_intel_pt
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
index 29aa1459306a..95bd5c3d1cce 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTOptions.td
@@ -11,7 +11,9 @@ let Command = "thread trace start intel pt" in {
Arg<"Value">,
Desc<"Trace size in bytes per thread. It must be a power of 2 greater "
"than or equal to 4096 (2^12). The trace is circular keeping "
- "the most recent data. Defaults to 4096 bytes.">;
+ "the most recent data. Defaults to 4096 bytes. It's possible to "
+ "specify size using multiples of unit bytes, e.g., 4KB, 1MB, 1MiB, "
+ "where 1K is 1024 bytes and 1M is 1048576 bytes.">;
def thread_trace_start_intel_pt_tsc: Option<"tsc", "t">,
Group<1>,
Desc<"Enable the use of TSC timestamps. This is supported on all devices "
@@ -40,7 +42,8 @@ let Command = "process trace start intel pt" in {
Arg<"Value">,
Desc<"Size in bytes used by each individual per-thread or per-cpu trace "
"buffer. It must be a power of 2 greater than or equal to 4096 (2^12) "
- "bytes.">;
+ "bytes. It's possible to specify a unit for these bytes, like 4KB, "
+ "16KiB or 1MB. Lower case units are allowed for convenience.">;
def process_trace_start_intel_pt_per_cpu_tracing:
Option<"per-cpu-tracing", "c">,
Group<1>,
@@ -53,7 +56,8 @@ let Command = "process trace start intel pt" in {
"option forces the capture of TSC timestamps (see --tsc). Also, this "
"option can't be used simulatenously with any other trace sessions "
"because of its system-wide nature.">;
- def process_trace_start_intel_pt_process_size_limit: Option<"total-size-limit", "l">,
+ def process_trace_start_intel_pt_process_size_limit:
+ Option<"total-size-limit", "l">,
Group<1>,
Arg<"Value">,
Desc<"Maximum total trace size per process in bytes. This limit applies to "
@@ -62,7 +66,9 @@ let Command = "process trace start intel pt" in {
"Whenever a thread is attempted to be traced due to this command and "
"the limit would be reached, the process is stopped with a "
"\"processor trace\" reason, so that the user can retrace the process "
- "if needed. Defaults to 500MB.">;
+ "if needed. Defaults to 500MB. It's possible to specify a unit for "
+ "these bytes, like 4KB, 16KiB or 1MB. Lower case units are allowed "
+ "for convenience.">;
def process_trace_start_intel_pt_tsc: Option<"tsc", "t">,
Group<1>,
Desc<"Enable the use of TSC timestamps. This is supported on all devices "
@@ -83,14 +89,9 @@ let Command = "process trace start intel pt" in {
"converted to the approximate number of raw trace bytes between PSB "
"packets as: 2 ^ (value + 11), e.g. value 3 means 16KiB between PSB "
"packets. Defaults to 0 if supported.">;
-}
-
-let Command = "process trace save intel pt" in {
- def process_trace_save_intel_directory: Option<"directory", "d">,
- Group<1>,
- Arg<"Value">, Required,
- Desc<"This value defines the directory where the trace will be saved."
- "It will be created if it does not exist. It will also create a "
- "trace files with the trace data and a trace.json with the main "
- "properties of the trace session.">;
+ def process_trace_start_intel_pt_disable_cgroup_filtering:
+ Option<"disable-cgroup-filtering", "d">,
+ Desc<"Disable the automatic cgroup filtering that is applied if --per-cpu "
+ "is provided. Cgroup filtering allows collecting intel pt data "
+ "exclusively of processes of the same cgroup as the target.">;
}
diff --git a/lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp b/lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp
index 7deeaf2bf10f..d8e44ee66de8 100644
--- a/lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp
+++ b/lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp
@@ -160,15 +160,15 @@ TraceHTR::TraceHTR(Thread &thread, TraceCursor &cursor)
cursor.Next();
} else {
lldb::addr_t current_instruction_load_address = cursor.GetLoadAddress();
- lldb::TraceInstructionControlFlowType current_instruction_type =
- cursor.GetInstructionControlFlowType();
+ lldb::InstructionControlFlowKind current_instruction_type =
+ cursor.GetInstructionControlFlowKind();
m_instruction_layer_up->AppendInstruction(
current_instruction_load_address);
cursor.Next();
bool more_data_in_trace = cursor.HasValue();
if (current_instruction_type &
- lldb::eTraceInstructionControlFlowTypeCall) {
+ lldb::eInstructionControlFlowKindCall) {
if (more_data_in_trace && !cursor.IsError()) {
m_instruction_layer_up->AddCallInstructionMetadata(
current_instruction_load_address,
diff --git a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
index ac5e316eecb0..03515a32ff86 100644
--- a/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
+++ b/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -83,6 +83,7 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
const bool show_address = true;
const bool show_bytes = true;
+ const bool show_control_flow_kind = true;
m_inst_emulator_up->GetRegisterInfo(unwind_plan.GetRegisterKind(),
unwind_plan.GetInitialCFARegister(),
m_cfa_reg_info);
@@ -244,7 +245,8 @@ bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
lldb_private::FormatEntity::Entry format;
FormatEntity::Parse("${frame.pc}: ", format);
inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize(), show_address,
- show_bytes, nullptr, nullptr, nullptr, &format, 0);
+ show_bytes, show_control_flow_kind, nullptr, nullptr,
+ nullptr, &format, 0);
log->PutString(strm.GetString());
}
diff --git a/lldb/source/Symbol/Function.cpp b/lldb/source/Symbol/Function.cpp
index 648a12524aed..8ec4bc90cd13 100644
--- a/lldb/source/Symbol/Function.cpp
+++ b/lldb/source/Symbol/Function.cpp
@@ -196,11 +196,10 @@ Function *IndirectCallEdge::GetCallee(ModuleList &images,
Log *log = GetLog(LLDBLog::Step);
Status error;
Value callee_addr_val;
- if (!call_target.Evaluate(&exe_ctx, exe_ctx.GetRegisterContext(),
- /*loclist_base_load_addr=*/LLDB_INVALID_ADDRESS,
- /*initial_value_ptr=*/nullptr,
- /*object_address_ptr=*/nullptr, callee_addr_val,
- &error)) {
+ if (!call_target.Evaluate(
+ &exe_ctx, exe_ctx.GetRegisterContext(), LLDB_INVALID_ADDRESS,
+ /*initial_value_ptr=*/nullptr,
+ /*object_address_ptr=*/nullptr, callee_addr_val, &error)) {
LLDB_LOGF(log, "IndirectCallEdge: Could not evaluate expression: %s",
error.AsCString());
return nullptr;
@@ -440,8 +439,9 @@ bool Function::GetDisassembly(const ExecutionContext &exe_ctx,
if (disassembler_sp) {
const bool show_address = true;
const bool show_bytes = false;
- disassembler_sp->GetInstructionList().Dump(&strm, show_address, show_bytes,
- &exe_ctx);
+ const bool show_control_flow_kind = false;
+ disassembler_sp->GetInstructionList().Dump(
+ &strm, show_address, show_bytes, show_control_flow_kind, &exe_ctx);
return true;
}
return false;
diff --git a/lldb/source/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp
index 9ec7f2638f71..668276aa2500 100644
--- a/lldb/source/Symbol/Symbol.cpp
+++ b/lldb/source/Symbol/Symbol.cpp
@@ -558,8 +558,9 @@ bool Symbol::GetDisassembly(const ExecutionContext &exe_ctx, const char *flavor,
if (disassembler_sp) {
const bool show_address = true;
const bool show_bytes = false;
- disassembler_sp->GetInstructionList().Dump(&strm, show_address, show_bytes,
- &exe_ctx);
+ const bool show_control_flow_kind = false;
+ disassembler_sp->GetInstructionList().Dump(
+ &strm, show_address, show_bytes, show_control_flow_kind, &exe_ctx);
return true;
}
return false;
diff --git a/lldb/source/Symbol/TypeList.cpp b/lldb/source/Symbol/TypeList.cpp
index ace715d933ea..494e59e3a0fc 100644
--- a/lldb/source/Symbol/TypeList.cpp
+++ b/lldb/source/Symbol/TypeList.cpp
@@ -97,7 +97,7 @@ void TypeList::Dump(Stream *s, bool show_context) {
}
}
-void TypeList::RemoveMismatchedTypes(const char *qualified_typename,
+void TypeList::RemoveMismatchedTypes(llvm::StringRef qualified_typename,
bool exact_match) {
llvm::StringRef type_scope;
llvm::StringRef type_basename;
@@ -107,13 +107,12 @@ void TypeList::RemoveMismatchedTypes(const char *qualified_typename,
type_basename = qualified_typename;
type_scope = "";
}
- return RemoveMismatchedTypes(std::string(type_scope),
- std::string(type_basename), type_class,
+ return RemoveMismatchedTypes(type_scope, type_basename, type_class,
exact_match);
}
-void TypeList::RemoveMismatchedTypes(const std::string &type_scope,
- const std::string &type_basename,
+void TypeList::RemoveMismatchedTypes(llvm::StringRef type_scope,
+ llvm::StringRef type_basename,
TypeClass type_class, bool exact_match) {
// Our "collection" type currently is a std::map which doesn't have any good
// way to iterate and remove items from the map so we currently just make a
diff --git a/lldb/source/Symbol/TypeMap.cpp b/lldb/source/Symbol/TypeMap.cpp
index 2cda9b6c27d1..0d5f6d53e5a0 100644
--- a/lldb/source/Symbol/TypeMap.cpp
+++ b/lldb/source/Symbol/TypeMap.cpp
@@ -127,23 +127,8 @@ void TypeMap::Dump(Stream *s, bool show_context, lldb::DescriptionLevel level) {
}
}
-void TypeMap::RemoveMismatchedTypes(const char *qualified_typename,
- bool exact_match) {
- llvm::StringRef type_scope;
- llvm::StringRef type_basename;
- TypeClass type_class = eTypeClassAny;
- if (!Type::GetTypeScopeAndBasename(qualified_typename, type_scope,
- type_basename, type_class)) {
- type_basename = qualified_typename;
- type_scope = "";
- }
- return RemoveMismatchedTypes(std::string(type_scope),
- std::string(type_basename), type_class,
- exact_match);
-}
-
-void TypeMap::RemoveMismatchedTypes(const std::string &type_scope,
- const std::string &type_basename,
+void TypeMap::RemoveMismatchedTypes(llvm::StringRef type_scope,
+ llvm::StringRef type_basename,
TypeClass type_class, bool exact_match) {
// Our "collection" type currently is a std::map which doesn't have any good
// way to iterate and remove items from the map so we currently just make a
@@ -214,25 +199,3 @@ void TypeMap::RemoveMismatchedTypes(const std::string &type_scope,
}
m_types.swap(matching_types);
}
-
-void TypeMap::RemoveMismatchedTypes(TypeClass type_class) {
- if (type_class == eTypeClassAny)
- return;
-
- // Our "collection" type currently is a std::map which doesn't have any good
- // way to iterate and remove items from the map so we currently just make a
- // new list and add all of the matching types to it, and then swap it into
- // m_types at the end
- collection matching_types;
-
- iterator pos, end = m_types.end();
-
- for (pos = m_types.begin(); pos != end; ++pos) {
- Type *the_type = pos->second.get();
- TypeClass match_type_class =
- the_type->GetForwardCompilerType().GetTypeClass();
- if (match_type_class & type_class)
- matching_types.insert(*pos);
- }
- m_types.swap(matching_types);
-}
diff --git a/lldb/source/Symbol/Variable.cpp b/lldb/source/Symbol/Variable.cpp
index b92c86654496..f65e73e5d049 100644
--- a/lldb/source/Symbol/Variable.cpp
+++ b/lldb/source/Symbol/Variable.cpp
@@ -39,13 +39,13 @@ Variable::Variable(lldb::user_id_t uid, const char *name, const char *mangled,
const lldb::SymbolFileTypeSP &symfile_type_sp,
ValueType scope, SymbolContextScope *context,
const RangeList &scope_range, Declaration *decl_ptr,
- const DWARFExpression &location, bool external,
+ const DWARFExpressionList &location_list, bool external,
bool artificial, bool location_is_constant_data,
bool static_member)
: UserID(uid), m_name(name), m_mangled(ConstString(mangled)),
m_symfile_type_sp(symfile_type_sp), m_scope(scope),
m_owner_scope(context), m_scope_range(scope_range),
- m_declaration(decl_ptr), m_location(location), m_external(external),
+ m_declaration(decl_ptr), m_location_list(location_list), m_external(external),
m_artificial(artificial), m_loc_is_const_data(location_is_constant_data),
m_static_member(static_member) {}
@@ -145,7 +145,7 @@ void Variable::Dump(Stream *s, bool show_context) const {
bool show_fullpaths = false;
m_declaration.Dump(s, show_fullpaths);
- if (m_location.IsValid()) {
+ if (m_location_list.IsValid()) {
s->PutCString(", location = ");
ABISP abi;
if (m_owner_scope) {
@@ -153,7 +153,7 @@ void Variable::Dump(Stream *s, bool show_context) const {
if (module_sp)
abi = ABI::FindPlugin(ProcessSP(), module_sp->GetArchitecture());
}
- m_location.GetDescription(s, lldb::eDescriptionLevelBrief, abi.get());
+ m_location_list.GetDescription(s, lldb::eDescriptionLevelBrief, abi.get());
}
if (m_external)
@@ -212,12 +212,6 @@ void Variable::CalculateSymbolContext(SymbolContext *sc) {
}
bool Variable::LocationIsValidForFrame(StackFrame *frame) {
- // Is the variable is described by a single location?
- if (!m_location.IsLocationList()) {
- // Yes it is, the location is valid.
- return true;
- }
-
if (frame) {
Function *function =
frame->GetSymbolContext(eSymbolContextFunction).function;
@@ -231,7 +225,7 @@ bool Variable::LocationIsValidForFrame(StackFrame *frame) {
return false;
// It is a location list. We just need to tell if the location list
// contains the current address when converted to a load address
- return m_location.LocationListContainsAddress(
+ return m_location_list.ContainsAddress(
loclist_base_load_addr,
frame->GetFrameCodeAddress().GetLoadAddress(target_sp.get()));
}
@@ -244,7 +238,7 @@ bool Variable::LocationIsValidForAddress(const Address &address) {
// function.
if (address.IsSectionOffset()) {
// We need to check if the address is valid for both scope range and value
- // range.
+ // range.
// Empty scope range means block range.
bool valid_in_scope_range =
GetScopeRange().IsEmpty() || GetScopeRange().FindEntryThatContains(
@@ -255,7 +249,7 @@ bool Variable::LocationIsValidForAddress(const Address &address) {
CalculateSymbolContext(&sc);
if (sc.module_sp == address.GetModule()) {
// Is the variable is described by a single location?
- if (!m_location.IsLocationList()) {
+ if (m_location_list.IsAlwaysValidSingleExpr()) {
// Yes it is, the location is valid.
return true;
}
@@ -267,8 +261,8 @@ bool Variable::LocationIsValidForAddress(const Address &address) {
return false;
// It is a location list. We just need to tell if the location list
// contains the current address when converted to a load address
- return m_location.LocationListContainsAddress(loclist_base_file_addr,
- address.GetFileAddress());
+ return m_location_list.ContainsAddress(loclist_base_file_addr,
+ address.GetFileAddress());
}
}
}
@@ -459,9 +453,9 @@ bool Variable::DumpLocations(Stream *s, const Address &address) {
sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
if (loclist_base_file_addr == LLDB_INVALID_ADDRESS)
return false;
- return m_location.DumpLocations(s, eDescriptionLevelBrief,
- loclist_base_file_addr, file_addr,
- abi.get());
+ return m_location_list.DumpLocations(s, eDescriptionLevelBrief,
+ loclist_base_file_addr, file_addr,
+ abi.get());
}
return false;
}
diff --git a/lldb/source/Target/RegisterContextUnwind.cpp b/lldb/source/Target/RegisterContextUnwind.cpp
index e98aed7e1555..a0f97d7e7cff 100644
--- a/lldb/source/Target/RegisterContextUnwind.cpp
+++ b/lldb/source/Target/RegisterContextUnwind.cpp
@@ -11,7 +11,7 @@
#include "lldb/Core/AddressRange.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Value.h"
-#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Expression/DWARFExpressionList.h"
#include "lldb/Symbol/ArmUnwindInfo.h"
#include "lldb/Symbol/CallFrameInfo.h"
#include "lldb/Symbol/DWARFCallFrameInfo.h"
@@ -381,7 +381,7 @@ void RegisterContextUnwind::InitializeNonZerothFrame() {
// symbol/function information - just stick in some reasonable defaults and
// hope we can unwind past this frame. If we're above a trap handler,
// we may be at a bogus address because we jumped through a bogus function
- // pointer and trapped, so don't force the arch default unwind plan in that
+ // pointer and trapped, so don't force the arch default unwind plan in that
// case.
ModuleSP pc_module_sp(m_current_pc.GetModule());
if ((!m_current_pc.IsValid() || !pc_module_sp) &&
@@ -1286,7 +1286,7 @@ RegisterContextUnwind::SavedLocationForRegister(
// arch default unwind plan is used as the Fast Unwind Plan, we
// need to recognize this & switch over to the Full Unwind Plan
// to see what unwind rule that (more knoweldgeable, probably)
- // UnwindPlan has. If the full UnwindPlan says the register
+ // UnwindPlan has. If the full UnwindPlan says the register
// location is Undefined, then it really is.
if (active_row->GetRegisterInfo(regnum.GetAsKind(unwindplan_registerkind),
unwindplan_regloc) &&
@@ -1335,13 +1335,13 @@ RegisterContextUnwind::SavedLocationForRegister(
m_full_unwind_plan_sp->GetReturnAddressRegister() !=
LLDB_INVALID_REGNUM) {
// If this is a trap handler frame, we should have access to
- // the complete register context when the interrupt/async
+ // the complete register context when the interrupt/async
// signal was received, we should fetch the actual saved $pc
// value instead of the Return Address register.
// If $pc is not available, fall back to the RA reg.
UnwindPlan::Row::RegisterLocation scratch;
if (m_frame_type == eTrapHandlerFrame &&
- active_row->GetRegisterInfo
+ active_row->GetRegisterInfo
(pc_regnum.GetAsKind (unwindplan_registerkind), scratch)) {
UnwindLogMsg("Providing pc register instead of rewriting to "
"RA reg because this is a trap handler and there is "
@@ -1642,8 +1642,9 @@ RegisterContextUnwind::SavedLocationForRegister(
process->GetByteOrder(),
process->GetAddressByteSize());
ModuleSP opcode_ctx;
- DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr);
- dwarfexpr.SetRegisterKind(unwindplan_registerkind);
+ DWARFExpressionList dwarfexpr(opcode_ctx, dwarfdata, nullptr);
+ dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind(
+ unwindplan_registerkind);
Value cfa_val = Scalar(m_cfa);
cfa_val.SetValueType(Value::ValueType::LoadAddress);
Value result;
@@ -2006,8 +2007,9 @@ bool RegisterContextUnwind::ReadFrameAddress(
process->GetByteOrder(),
process->GetAddressByteSize());
ModuleSP opcode_ctx;
- DWARFExpression dwarfexpr(opcode_ctx, dwarfdata, nullptr);
- dwarfexpr.SetRegisterKind(row_register_kind);
+ DWARFExpressionList dwarfexpr(opcode_ctx, dwarfdata, nullptr);
+ dwarfexpr.GetMutableExpressionAtAddress()->SetRegisterKind(
+ row_register_kind);
Value result;
Status error;
if (dwarfexpr.Evaluate(&exe_ctx, this, 0, nullptr, nullptr, result,
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 1e3dbc73a04e..e87cf5af3e39 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -1087,7 +1087,7 @@ bool StackFrame::GetFrameBaseValue(Scalar &frame_base, Status *error_ptr) {
ExecutionContext exe_ctx(shared_from_this());
Value expr_value;
addr_t loclist_base_addr = LLDB_INVALID_ADDRESS;
- if (m_sc.function->GetFrameBaseExpression().IsLocationList())
+ if (!m_sc.function->GetFrameBaseExpression().IsAlwaysValidSingleExpr())
loclist_base_addr =
m_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(
exe_ctx.GetTargetPtr());
@@ -1116,7 +1116,7 @@ bool StackFrame::GetFrameBaseValue(Scalar &frame_base, Status *error_ptr) {
return m_frame_base_error.Success();
}
-DWARFExpression *StackFrame::GetFrameBaseExpression(Status *error_ptr) {
+DWARFExpressionList *StackFrame::GetFrameBaseExpression(Status *error_ptr) {
if (!m_sc.function) {
if (error_ptr) {
error_ptr->SetErrorString("No function in symbol context.");
@@ -1200,7 +1200,7 @@ lldb::LanguageType StackFrame::GuessLanguage() {
LanguageType lang_type = GetLanguage();
if (lang_type == eLanguageTypeUnknown) {
- SymbolContext sc = GetSymbolContext(eSymbolContextFunction
+ SymbolContext sc = GetSymbolContext(eSymbolContextFunction
| eSymbolContextSymbol);
if (sc.function) {
lang_type = sc.function->GetMangled().GuessLanguage();
@@ -1417,7 +1417,7 @@ ValueObjectSP GetValueForDereferincingOffset(StackFrame &frame,
Status error;
ValueObjectSP pointee = base->Dereference(error);
-
+
if (!pointee) {
return ValueObjectSP();
}
@@ -1505,7 +1505,7 @@ lldb::ValueObjectSP DoGuessValueAt(StackFrame &frame, ConstString reg,
Instruction::Operand::BuildRegister(reg));
for (VariableSP var_sp : variables) {
- if (var_sp->LocationExpression().MatchesOperand(frame, op))
+ if (var_sp->LocationExpressionList().MatchesOperand(frame, op))
return frame.GetValueObjectForFrameVariable(var_sp, eNoDynamicValues);
}
diff --git a/lldb/source/Target/ThreadPlanTracer.cpp b/lldb/source/Target/ThreadPlanTracer.cpp
index f2346fc237ce..f5331428038b 100644
--- a/lldb/source/Target/ThreadPlanTracer.cpp
+++ b/lldb/source/Target/ThreadPlanTracer.cpp
@@ -170,13 +170,14 @@ void ThreadPlanAssemblyTracer::Log() {
if (instruction_list.GetSize()) {
const bool show_bytes = true;
const bool show_address = true;
+ const bool show_control_flow_kind = true;
Instruction *instruction =
instruction_list.GetInstructionAtIndex(0).get();
const FormatEntity::Entry *disassemble_format =
m_process.GetTarget().GetDebugger().GetDisassemblyFormat();
instruction->Dump(stream, max_opcode_byte_size, show_address,
- show_bytes, nullptr, nullptr, nullptr,
- disassemble_format, 0);
+ show_bytes, show_control_flow_kind, nullptr, nullptr,
+ nullptr, disassemble_format, 0);
}
}
}
diff --git a/lldb/source/Target/TraceCursor.cpp b/lldb/source/Target/TraceCursor.cpp
index 1c3fabc4dec0..f99b0d28c154 100644
--- a/lldb/source/Target/TraceCursor.cpp
+++ b/lldb/source/Target/TraceCursor.cpp
@@ -48,5 +48,8 @@ const char *TraceCursor::EventKindToString(lldb::TraceEvent event_kind) {
return "hardware disabled tracing";
case lldb::eTraceEventDisabledSW:
return "software disabled tracing";
+ case lldb::eTraceEventCPUChanged:
+ return "CPU core changed";
}
+ llvm_unreachable("Fully covered switch above");
}
diff --git a/lldb/source/Target/TraceDumper.cpp b/lldb/source/Target/TraceDumper.cpp
index 6a5fd0268e02..739105e9e9fb 100644
--- a/lldb/source/Target/TraceDumper.cpp
+++ b/lldb/source/Target/TraceDumper.cpp
@@ -129,32 +129,30 @@ public:
m_s.Format(" {0}: ", item.id);
if (m_options.show_tsc) {
- m_s << "[tsc=";
-
- if (item.tsc)
- m_s.Format("{0}", *item.tsc);
- else
- m_s << "unavailable";
-
- m_s << "] ";
+ m_s.Format("[tsc={0}] ",
+ item.tsc ? std::to_string(*item.tsc) : "unavailable");
}
if (item.event) {
m_s << "(event) " << TraceCursor::EventKindToString(*item.event);
+ if (*item.event == eTraceEventCPUChanged) {
+ m_s.Format(" [new CPU={0}]",
+ item.cpu_id ? std::to_string(*item.cpu_id) : "unavailable");
+ }
} else if (item.error) {
m_s << "(error) " << *item.error;
} else {
m_s.Format("{0:x+16}", item.load_address);
- if (item.symbol_info) {
+ if (item.symbol_info && item.symbol_info->instruction) {
m_s << " ";
- item.symbol_info->instruction->Dump(&m_s, /*max_opcode_byte_size=*/0,
- /*show_address=*/false,
- /*show_bytes=*/false,
- &item.symbol_info->exe_ctx,
- &item.symbol_info->sc,
- /*prev_sym_ctx=*/nullptr,
- /*disassembly_addr_format=*/nullptr,
- /*max_address_text_size=*/0);
+ item.symbol_info->instruction->Dump(
+ &m_s, /*max_opcode_byte_size=*/0,
+ /*show_address=*/false,
+ /*show_bytes=*/false, m_options.show_control_flow_kind,
+ &item.symbol_info->exe_ctx, &item.symbol_info->sc,
+ /*prev_sym_ctx=*/nullptr,
+ /*disassembly_addr_format=*/nullptr,
+ /*max_address_text_size=*/0);
}
}
@@ -172,14 +170,16 @@ class OutputWriterJSON : public TraceDumper::OutputWriter {
/* schema:
error_message: string
| {
+ "event": string,
"id": decimal,
"tsc"?: string decimal,
- "event": string
+ "cpuId"? decimal,
} | {
+ "error": string,
"id": decimal,
"tsc"?: string decimal,
- "error": string,
| {
+ "loadAddress": string decimal,
"id": decimal,
"tsc"?: string decimal,
"module"?: string,
@@ -200,6 +200,37 @@ public:
~OutputWriterJSON() { m_j.arrayEnd(); }
+ void DumpEvent(const TraceDumper::TraceItem &item) {
+ m_j.attribute("event", TraceCursor::EventKindToString(*item.event));
+ if (item.event == eTraceEventCPUChanged)
+ m_j.attribute("cpuId", item.cpu_id);
+ }
+
+ void DumpInstruction(const TraceDumper::TraceItem &item) {
+ m_j.attribute("loadAddress", formatv("{0:x}", item.load_address));
+ if (item.symbol_info) {
+ m_j.attribute("module", ToOptionalString(GetModuleName(item)));
+ m_j.attribute(
+ "symbol",
+ ToOptionalString(item.symbol_info->sc.GetFunctionName().AsCString()));
+
+ if (item.symbol_info->instruction) {
+ m_j.attribute("mnemonic",
+ ToOptionalString(item.symbol_info->instruction->GetMnemonic(
+ &item.symbol_info->exe_ctx)));
+ }
+
+ if (IsLineEntryValid(item.symbol_info->sc.line_entry)) {
+ m_j.attribute(
+ "source",
+ ToOptionalString(
+ item.symbol_info->sc.line_entry.file.GetPath().c_str()));
+ m_j.attribute("line", item.symbol_info->sc.line_entry.line);
+ m_j.attribute("column", item.symbol_info->sc.line_entry.column);
+ }
+ }
+ }
+
void TraceItem(const TraceDumper::TraceItem &item) override {
m_j.object([&] {
m_j.attribute("id", item.id);
@@ -209,37 +240,11 @@ public:
item.tsc ? Optional<std::string>(std::to_string(*item.tsc)) : None);
if (item.event) {
- m_j.object([&] {
- m_j.attribute("event", TraceCursor::EventKindToString(*item.event));
- });
- return;
- }
-
- if (item.error) {
+ DumpEvent(item);
+ } else if (item.error) {
m_j.attribute("error", *item.error);
- return;
- }
-
- // we know we are seeing an actual instruction
- m_j.attribute("loadAddress", formatv("{0:x}", item.load_address));
- if (item.symbol_info) {
- m_j.attribute("module", ToOptionalString(GetModuleName(item)));
- m_j.attribute("symbol",
- ToOptionalString(
- item.symbol_info->sc.GetFunctionName().AsCString()));
- m_j.attribute(
- "mnemonic",
- ToOptionalString(item.symbol_info->instruction->GetMnemonic(
- &item.symbol_info->exe_ctx)));
-
- if (IsLineEntryValid(item.symbol_info->sc.line_entry)) {
- m_j.attribute(
- "source",
- ToOptionalString(
- item.symbol_info->sc.line_entry.file.GetPath().c_str()));
- m_j.attribute("line", item.symbol_info->sc.line_entry.line);
- m_j.attribute("column", item.symbol_info->sc.line_entry.column);
- }
+ } else {
+ DumpInstruction(item);
}
});
}
@@ -361,6 +366,8 @@ 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)
+ item.cpu_id = m_cursor_up->GetCPU();
} else if (m_cursor_up->IsError()) {
item.error = m_cursor_up->GetError();
} else {
diff --git a/lldb/source/Utility/Args.cpp b/lldb/source/Utility/Args.cpp
index 3978f9422653..daccb91d8436 100644
--- a/lldb/source/Utility/Args.cpp
+++ b/lldb/source/Utility/Args.cpp
@@ -385,6 +385,7 @@ std::string Args::GetShellSafeArgument(const FileSpec &shell,
};
static ShellDescriptor g_Shells[] = {{ConstString("bash"), " '\"<>()&;"},
+ {ConstString("fish"), " '\"<>()&\\|;"},
{ConstString("tcsh"), " '\"<>()&;"},
{ConstString("zsh"), " '\"<>()&;\\|"},
{ConstString("sh"), " '\"<>()&;"}};
diff --git a/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp b/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
index 1ad74cacc4c3..7a0ed9c53c65 100644
--- a/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
+++ b/lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
@@ -53,7 +53,8 @@ bool fromJSON(const json::Value &value, TraceIntelPTStartRequest &packet,
if (packet.IsProcessTracing()) {
if (!o.map("processBufferSizeLimit", packet.process_buffer_size_limit) ||
- !o.map("perCpuTracing", packet.per_cpu_tracing))
+ !o.map("perCpuTracing", packet.per_cpu_tracing) ||
+ !o.map("disableCgroupTracing", packet.disable_cgroup_filtering))
return false;
}
return true;
@@ -67,6 +68,7 @@ json::Value toJSON(const TraceIntelPTStartRequest &packet) {
obj.try_emplace("psbPeriod", packet.psb_period);
obj.try_emplace("enableTsc", packet.enable_tsc);
obj.try_emplace("perCpuTracing", packet.per_cpu_tracing);
+ obj.try_emplace("disableCgroupTracing", packet.disable_cgroup_filtering);
return base;
}
@@ -108,13 +110,15 @@ bool fromJSON(const json::Value &value, TraceIntelPTGetStateResponse &packet,
json::Path path) {
ObjectMapper o(value, path);
return o && fromJSON(value, (TraceGetStateResponse &)packet, path) &&
- o.map("tscPerfZeroConversion", packet.tsc_perf_zero_conversion);
+ o.map("tscPerfZeroConversion", packet.tsc_perf_zero_conversion) &&
+ o.map("usingCgroupFiltering", packet.using_cgroup_filtering);
}
json::Value toJSON(const TraceIntelPTGetStateResponse &packet) {
json::Value base = toJSON((const TraceGetStateResponse &)packet);
- base.getAsObject()->insert(
- {"tscPerfZeroConversion", packet.tsc_perf_zero_conversion});
+ json::Object &obj = *base.getAsObject();
+ obj.insert({"tscPerfZeroConversion", packet.tsc_perf_zero_conversion});
+ obj.insert({"usingCgroupFiltering", packet.using_cgroup_filtering});
return base;
}