Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions lldb/include/lldb/API/SBTarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,14 @@ class LLDB_API SBTarget {
lldb::LanguageType symbol_language,
const SBFileSpecList &module_list, const SBFileSpecList &comp_unit_list);

lldb::SBBreakpoint BreakpointCreateByName(
const char *symbol_name,
uint32_t
name_type_mask, // Logical OR one or more FunctionNameType enum bits
lldb::LanguageType symbol_language, lldb::addr_t offset,
bool offset_is_insn_count, const SBFileSpecList &module_list,
const SBFileSpecList &comp_unit_list);

#ifdef SWIG
lldb::SBBreakpoint BreakpointCreateByNames(
const char **symbol_name, uint32_t num_names,
Expand Down
9 changes: 6 additions & 3 deletions lldb/include/lldb/Breakpoint/BreakpointResolver.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ class BreakpointResolver : public Searcher {
/// The breakpoint that owns this resolver.
/// \param[in] resolverType
/// The concrete breakpoint resolver type for this breakpoint.
BreakpointResolver(const lldb::BreakpointSP &bkpt,
unsigned char resolverType,
lldb::addr_t offset = 0);
BreakpointResolver(const lldb::BreakpointSP &bkpt, unsigned char resolverType,
lldb::addr_t offset = 0,
bool offset_is_insn_count = false);

/// The Destructor is virtual, all significant breakpoint resolvers derive
/// from this class.
Expand Down Expand Up @@ -76,6 +76,7 @@ class BreakpointResolver : public Searcher {
void SetOffset(lldb::addr_t offset);

lldb::addr_t GetOffset() const { return m_offset; }
lldb::addr_t GetOffsetIsInsnCount() const { return m_offset_is_insn_count; }

/// In response to this method the resolver scans all the modules in the
/// breakpoint's target, and adds any new locations it finds.
Expand Down Expand Up @@ -220,6 +221,8 @@ class BreakpointResolver : public Searcher {
lldb::BreakpointWP m_breakpoint; // This is the breakpoint we add locations to.
lldb::addr_t m_offset; // A random offset the user asked us to add to any
// breakpoints we set.
bool m_offset_is_insn_count; // Use the offset as an instruction count
// instead of an address offset.

// Subclass identifier (for llvm isa/dyn_cast)
const unsigned char SubclassID;
Expand Down
2 changes: 1 addition & 1 deletion lldb/include/lldb/Breakpoint/BreakpointResolverName.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class BreakpointResolverName : public BreakpointResolver {
lldb::FunctionNameType name_type_mask,
lldb::LanguageType language,
Breakpoint::MatchType type, lldb::addr_t offset,
bool skip_prologue);
bool offset_is_insn_count, bool skip_prologue);

// This one takes an array of names. It is always MatchType = Exact.
BreakpointResolverName(const lldb::BreakpointSP &bkpt, const char *names[],
Expand Down
2 changes: 2 additions & 0 deletions lldb/include/lldb/Core/Disassembler.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ class InstructionList {

size_t GetSize() const;

size_t GetTotalByteSize() const;

uint32_t GetMaxOpcocdeByteSize() const;

lldb::InstructionSP GetInstructionAtIndex(size_t idx) const;
Expand Down
11 changes: 8 additions & 3 deletions lldb/include/lldb/Target/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "lldb/Breakpoint/BreakpointList.h"
#include "lldb/Breakpoint/BreakpointName.h"
#include "lldb/Breakpoint/WatchpointList.h"
#include "lldb/Core/Address.h"
#include "lldb/Core/Architecture.h"
#include "lldb/Core/Disassembler.h"
#include "lldb/Core/ModuleList.h"
Expand Down Expand Up @@ -723,7 +724,7 @@ class Target : public std::enable_shared_from_this<Target>,
lldb::BreakpointSP CreateBreakpoint(lldb::addr_t load_addr, bool internal,
bool request_hardware);

// Use this to create a breakpoint from a load address and a module file spec
// Use this to create a breakpoint from a file address and a module file spec
lldb::BreakpointSP CreateAddressInModuleBreakpoint(lldb::addr_t file_addr,
bool internal,
const FileSpec &file_spec,
Expand Down Expand Up @@ -752,8 +753,8 @@ class Target : public std::enable_shared_from_this<Target>,
const FileSpecList *containingModules,
const FileSpecList *containingSourceFiles, const char *func_name,
lldb::FunctionNameType func_name_type_mask, lldb::LanguageType language,
lldb::addr_t offset, LazyBool skip_prologue, bool internal,
bool request_hardware);
lldb::addr_t offset, bool offset_is_insn_count, LazyBool skip_prologue,
bool internal, bool request_hardware);

lldb::BreakpointSP
CreateExceptionBreakpoint(enum lldb::LanguageType language, bool catch_bp,
Expand Down Expand Up @@ -1334,6 +1335,10 @@ class Target : public std::enable_shared_from_this<Target>,
const lldb_private::RegisterFlags &flags,
uint32_t byte_size);

llvm::Expected<lldb::DisassemblerSP>
ReadInstructions(const Address &start_addr, uint32_t count,
const char *flavor_string = nullptr);

// Target Stop Hooks
class StopHook : public UserID {
public:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,24 +107,33 @@ def dump_dap_log(log_file):

class Source(object):
def __init__(
self, path: Optional[str] = None, source_reference: Optional[int] = None
self,
path: Optional[str] = None,
source_reference: Optional[int] = None,
raw_dict: Optional[dict[str, Any]] = None,
):
self._name = None
self._path = None
self._source_reference = None
self._raw_dict = None

if path is not None:
self._name = os.path.basename(path)
self._path = path
elif source_reference is not None:
self._source_reference = source_reference
elif raw_dict is not None:
self._raw_dict = raw_dict
else:
raise ValueError("Either path or source_reference must be provided")

def __str__(self):
return f"Source(name={self.name}, path={self.path}), source_reference={self.source_reference})"

def as_dict(self):
if self._raw_dict is not None:
return self._raw_dict

source_dict = {}
if self._name is not None:
source_dict["name"] = self._name
Expand All @@ -135,6 +144,19 @@ def as_dict(self):
return source_dict


class Breakpoint(object):
def __init__(self, obj):
self._breakpoint = obj

def is_verified(self):
"""Check if the breakpoint is verified."""
return self._breakpoint.get("verified", False)

def source(self):
"""Get the source of the breakpoint."""
return self._breakpoint.get("source", {})


class NotSupportedError(KeyError):
"""Raised if a feature is not supported due to its capabilities."""

Expand Down Expand Up @@ -170,7 +192,7 @@ def __init__(
self.initialized = False
self.frame_scopes = {}
self.init_commands = init_commands
self.resolved_breakpoints = {}
self.resolved_breakpoints: dict[str, Breakpoint] = {}

@classmethod
def encode_content(cls, s: str) -> bytes:
Expand Down Expand Up @@ -326,8 +348,8 @@ def _process_continued(self, all_threads_continued: bool):
def _update_verified_breakpoints(self, breakpoints: list[Event]):
for breakpoint in breakpoints:
if "id" in breakpoint:
self.resolved_breakpoints[str(breakpoint["id"])] = breakpoint.get(
"verified", False
self.resolved_breakpoints[str(breakpoint["id"])] = Breakpoint(
breakpoint
)

def send_packet(self, command_dict: Request, set_sequence=True):
Expand Down Expand Up @@ -484,7 +506,14 @@ def wait_for_breakpoints_to_be_verified(
if breakpoint_event is None:
break

return [id for id in breakpoint_ids if id not in self.resolved_breakpoints]
return [
id
for id in breakpoint_ids
if (
id not in self.resolved_breakpoints
or not self.resolved_breakpoints[id].is_verified()
)
]

def wait_for_exited(self, timeout: Optional[float] = None):
event_dict = self.wait_for_event("exited", timeout=timeout)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,24 +59,22 @@ def set_source_breakpoints(
Each object in data is 1:1 mapping with the entry in lines.
It contains optional location/hitCondition/logMessage parameters.
"""
response = self.dap_server.request_setBreakpoints(
Source(source_path), lines, data
return self.set_source_breakpoints_from_source(
Source(path=source_path), lines, data, wait_for_resolve
)
if response is None or not response["success"]:
return []
breakpoints = response["body"]["breakpoints"]
breakpoint_ids = []
for breakpoint in breakpoints:
breakpoint_ids.append("%i" % (breakpoint["id"]))
if wait_for_resolve:
self.wait_for_breakpoints_to_resolve(breakpoint_ids)
return breakpoint_ids

def set_source_breakpoints_assembly(
self, source_reference, lines, data=None, wait_for_resolve=True
):
return self.set_source_breakpoints_from_source(
Source(source_reference=source_reference), lines, data, wait_for_resolve
)

def set_source_breakpoints_from_source(
self, source: Source, lines, data=None, wait_for_resolve=True
):
response = self.dap_server.request_setBreakpoints(
Source(source_reference=source_reference),
source,
lines,
data,
)
Expand Down
46 changes: 21 additions & 25 deletions lldb/source/API/SBTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -766,16 +766,19 @@ SBBreakpoint SBTarget::BreakpointCreateByName(const char *symbol_name,
const bool hardware = false;
const LazyBool skip_prologue = eLazyBoolCalculate;
const lldb::addr_t offset = 0;
const bool offset_is_insn_count = false;
if (module_name && module_name[0]) {
FileSpecList module_spec_list;
module_spec_list.Append(FileSpec(module_name));
sb_bp = target_sp->CreateBreakpoint(
&module_spec_list, nullptr, symbol_name, eFunctionNameTypeAuto,
eLanguageTypeUnknown, offset, skip_prologue, internal, hardware);
eLanguageTypeUnknown, offset, offset_is_insn_count, skip_prologue,
internal, hardware);
} else {
sb_bp = target_sp->CreateBreakpoint(
nullptr, nullptr, symbol_name, eFunctionNameTypeAuto,
eLanguageTypeUnknown, offset, skip_prologue, internal, hardware);
eLanguageTypeUnknown, offset, offset_is_insn_count, skip_prologue,
internal, hardware);
}
}

Expand Down Expand Up @@ -811,6 +814,17 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateByName(
const SBFileSpecList &comp_unit_list) {
LLDB_INSTRUMENT_VA(this, symbol_name, name_type_mask, symbol_language,
module_list, comp_unit_list);
return BreakpointCreateByName(symbol_name, name_type_mask, symbol_language, 0,
false, module_list, comp_unit_list);
}

lldb::SBBreakpoint SBTarget::BreakpointCreateByName(
const char *symbol_name, uint32_t name_type_mask,
LanguageType symbol_language, lldb::addr_t offset,
bool offset_is_insn_count, const SBFileSpecList &module_list,
const SBFileSpecList &comp_unit_list) {
LLDB_INSTRUMENT_VA(this, symbol_name, name_type_mask, symbol_language, offset,
offset_is_insn_count, module_list, comp_unit_list);

SBBreakpoint sb_bp;
if (TargetSP target_sp = GetSP();
Expand All @@ -821,7 +835,8 @@ lldb::SBBreakpoint SBTarget::BreakpointCreateByName(
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
FunctionNameType mask = static_cast<FunctionNameType>(name_type_mask);
sb_bp = target_sp->CreateBreakpoint(module_list.get(), comp_unit_list.get(),
symbol_name, mask, symbol_language, 0,
symbol_name, mask, symbol_language,
offset, offset_is_insn_count,
skip_prologue, internal, hardware);
}

Expand Down Expand Up @@ -1955,29 +1970,10 @@ lldb::SBInstructionList SBTarget::ReadInstructions(lldb::SBAddress base_addr,

if (TargetSP target_sp = GetSP()) {
if (Address *addr_ptr = base_addr.get()) {
DataBufferHeap data(
target_sp->GetArchitecture().GetMaximumOpcodeByteSize() * count, 0);
bool force_live_memory = true;
lldb_private::Status error;
lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
const size_t bytes_read =
target_sp->ReadMemory(*addr_ptr, data.GetBytes(), data.GetByteSize(),
error, force_live_memory, &load_addr);

const bool data_from_file = load_addr == LLDB_INVALID_ADDRESS;
if (!flavor_string || flavor_string[0] == '\0') {
// FIXME - we don't have the mechanism in place to do per-architecture
// settings. But since we know that for now we only support flavors on
// x86 & x86_64,
const llvm::Triple::ArchType arch =
target_sp->GetArchitecture().GetTriple().getArch();
if (arch == llvm::Triple::x86 || arch == llvm::Triple::x86_64)
flavor_string = target_sp->GetDisassemblyFlavor();
if (llvm::Expected<DisassemblerSP> disassembler =
target_sp->ReadInstructions(*addr_ptr, count, flavor_string)) {
sb_instructions.SetDisassembler(*disassembler);
}
sb_instructions.SetDisassembler(Disassembler::DisassembleBytes(
target_sp->GetArchitecture(), nullptr, flavor_string,
target_sp->GetDisassemblyCPU(), target_sp->GetDisassemblyFeatures(),
*addr_ptr, data.GetBytes(), bytes_read, count, data_from_file));
}
}

Expand Down
39 changes: 33 additions & 6 deletions lldb/source/Breakpoint/BreakpointResolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ const char *BreakpointResolver::g_ty_to_name[] = {"FileAndLine", "Address",

const char *BreakpointResolver::g_option_names[static_cast<uint32_t>(
BreakpointResolver::OptionNames::LastOptionName)] = {
"AddressOffset", "Exact", "FileName", "Inlines", "Language",
"LineNumber", "Column", "ModuleName", "NameMask", "Offset",
"PythonClass", "Regex", "ScriptArgs", "SectionName", "SearchDepth",
"AddressOffset", "Exact", "FileName", "Inlines", "Language",
"LineNumber", "Column", "ModuleName", "NameMask", "Offset",
"PythonClass", "Regex", "ScriptArgs", "SectionName", "SearchDepth",
"SkipPrologue", "SymbolNames"};

const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) {
Expand All @@ -65,8 +65,10 @@ BreakpointResolver::NameToResolverTy(llvm::StringRef name) {

BreakpointResolver::BreakpointResolver(const BreakpointSP &bkpt,
const unsigned char resolverTy,
lldb::addr_t offset)
: m_breakpoint(bkpt), m_offset(offset), SubclassID(resolverTy) {}
lldb::addr_t offset,
bool offset_is_insn_count)
: m_breakpoint(bkpt), m_offset(offset),
m_offset_is_insn_count(offset_is_insn_count), SubclassID(resolverTy) {}

BreakpointResolver::~BreakpointResolver() = default;

Expand Down Expand Up @@ -364,7 +366,32 @@ void BreakpointResolver::AddLocation(SearchFilter &filter,

BreakpointLocationSP BreakpointResolver::AddLocation(Address loc_addr,
bool *new_location) {
loc_addr.Slide(m_offset);
if (m_offset_is_insn_count) {
Target &target = GetBreakpoint()->GetTarget();
llvm::Expected<DisassemblerSP> expected_instructions =
target.ReadInstructions(loc_addr, m_offset);
if (!expected_instructions) {
LLDB_LOG_ERROR(GetLog(LLDBLog::Breakpoints),
expected_instructions.takeError(),
"error: Unable to read instructions at address 0x{0:x}",
loc_addr.GetLoadAddress(&target));
return BreakpointLocationSP();
}

const DisassemblerSP instructions = *expected_instructions;
if (!instructions ||
instructions->GetInstructionList().GetSize() != m_offset) {
LLDB_LOG(GetLog(LLDBLog::Breakpoints),
"error: Unable to read {0} instructions at address 0x{1:x}",
m_offset, loc_addr.GetLoadAddress(&target));
return BreakpointLocationSP();
}

loc_addr.Slide(instructions->GetInstructionList().GetTotalByteSize());
} else {
loc_addr.Slide(m_offset);
}

return GetBreakpoint()->AddLocation(loc_addr, new_location);
}

Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Breakpoint/BreakpointResolverAddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ Searcher::CallbackReturn BreakpointResolverAddress::SearchCallback(
Address tmp_address;
if (module_sp->ResolveFileAddress(m_addr.GetOffset(), tmp_address))
m_addr = tmp_address;
else
return Searcher::eCallbackReturnStop;
} else {
// If we didn't find the module, then we can't resolve the address.
return Searcher::eCallbackReturnStop;
}
}

Expand Down
Loading
Loading