Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
e4156c5
[lldb] Fix a crash in lldb-server during RemoveSoftwareBreakpoint() (…
royitaqi Jul 16, 2025
af47436
[lldb-dap] Fix type req->arguments == "disconnect" (#149446)
kusmour Jul 18, 2025
96a3aaf
[lldb-dap] Allow returning multiple breakpoints in "stopped" event (#…
SLTozer Jul 22, 2025
f984e48
[lldb-dap] support moduleId in the stackTrace response (#149774)
woruyu Aug 1, 2025
aa1f117
[vscode-lldb] Fix format (#151829)
royitaqi Aug 4, 2025
22ea1d5
Logging setup for lldb-dap extension (#146884)
award999 Aug 5, 2025
0890afc
[lldb-dap] Bump the version to 0.2.16
JDevlieghere Aug 5, 2025
8a8ead6
[vscode-lldb] Fix `yarn package` (#152002)
royitaqi Aug 5, 2025
cdadfab
[lldb] Treat address found via function name as a callable address (#…
DavidSpickett Aug 6, 2025
b3e2b85
[vscode-lldb] Fix race condition when changing lldb-dap arguments (#1…
royitaqi Aug 6, 2025
dd49810
[vscode-lldb] Add VS Code commands for high level debug workflow (#15…
royitaqi Aug 6, 2025
3c6c6b2
[lldb][test] Disable TestDAP_memory.py on 32-bit Arm Linux
DavidSpickett Aug 8, 2025
2612df6
[lldb-dap] persistent assembly breakpoints (#148061)
eronnen Aug 8, 2025
a2d0c7b
[lldb] Fix warnings
kazutakahirata Aug 8, 2025
5534767
[lldb][lldb-dap][test] Disable part of TestDAP_launch on Arm 32-bit
DavidSpickett Aug 15, 2025
592682a
[lldb][lldb-dap][test] Correct skip in TestDAP_launch
DavidSpickett Aug 15, 2025
6e115f0
[lldb] Adjust for CreateBreakpoint API change
JDevlieghere Oct 9, 2025
4078c20
[lldb][test] Fix typo in decorator
DavidSpickett Aug 8, 2025
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
23 changes: 23 additions & 0 deletions lldb/docs/resources/lldbdap.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,26 @@ This is also very simple, just run:
```bash
npm run format
```

## Working with the VS Code extension from another extension

The VS Code extension exposes the following [VS Code
commands](https://code.visualstudio.com/api/extension-guides/command),
which can be invoked by other debugger extensions to leverage this extension's
settings and logic. The commands help resolve configuration, create adapter
descriptor, and get the lldb-dap process for state tracking, additional
interaction, and telemetry.

```
// Resolve debug configuration
const resolvedConfiguration = await vscode.commands.executeCommand("lldb-dap.resolveDebugConfiguration", folder, configuration, token);

// Resolve debug configuration with substituted variables
const resolvedConfigurationWithSubstitutedVariables = await vscode.commands.executeCommand("lldb-dap.resolveDebugConfigurationWithSubstitutedVariables", folder, configuration, token);

// Create debug adapter descriptor
const adapterDescriptor = await vscode.commands.executeCommand("lldb-dap.createDebugAdapterDescriptor", session, executable);

// Get DAP server process
const process = await vscode.commands.executeCommand("lldb-dap.getServerProcess");
```
8 changes: 8 additions & 0 deletions lldb/include/lldb/API/SBTarget.h
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,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 @@ -19,6 +19,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 @@ -817,7 +818,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 @@ -846,8 +847,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 @@ -1438,6 +1439,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 Expand Up @@ -173,6 +171,28 @@ def verify_breakpoint_hit(self, breakpoint_ids, timeout=DEFAULT_TIMEOUT):
return
self.assertTrue(False, f"breakpoint not hit, stopped_events={stopped_events}")

def verify_all_breakpoints_hit(self, breakpoint_ids, timeout=DEFAULT_TIMEOUT):
"""Wait for the process we are debugging to stop, and verify we hit
all of the breakpoint locations in the "breakpoint_ids" array.
"breakpoint_ids" should be a list of int breakpoint IDs ([1, 2])."""
stopped_events = self.dap_server.wait_for_stopped(timeout)
for stopped_event in stopped_events:
if "body" in stopped_event:
body = stopped_event["body"]
if "reason" not in body:
continue
if (
body["reason"] != "breakpoint"
and body["reason"] != "instruction breakpoint"
):
continue
if "hitBreakpointIds" not in body:
continue
hit_bps = body["hitBreakpointIds"]
if all(breakpoint_id in hit_bps for breakpoint_id in breakpoint_ids):
return
self.assertTrue(False, f"breakpoints not hit, stopped_events={stopped_events}")

def verify_stop_exception_info(self, expected_description, timeout=DEFAULT_TIMEOUT):
"""Wait for the process we are debugging to stop, and verify the stop
reason is 'exception' and that the description matches
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 @@ -771,16 +771,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 @@ -816,6 +819,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 @@ -826,7 +840,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 @@ -2013,29 +2028,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
Loading