137 lines · cpp
1//===-- Breakpoint.cpp ----------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Breakpoint.h"10#include "DAP.h"11#include "LLDBUtils.h"12#include "Protocol/DAPTypes.h"13#include "ProtocolUtils.h"14#include "lldb/API/SBAddress.h"15#include "lldb/API/SBBreakpointLocation.h"16#include "lldb/API/SBFileSpec.h"17#include "lldb/API/SBLineEntry.h"18#include "lldb/API/SBModule.h"19#include "lldb/API/SBMutex.h"20#include "llvm/ADT/StringExtras.h"21#include <cstddef>22#include <cstdint>23#include <mutex>24#include <string>25 26using namespace lldb_dap;27 28static std::optional<protocol::PersistenceData>29GetPersistenceDataForSymbol(lldb::SBSymbol &symbol) {30 protocol::PersistenceData persistence_data;31 lldb::SBModule module = symbol.GetStartAddress().GetModule();32 if (!module.IsValid())33 return std::nullopt;34 35 lldb::SBFileSpec file_spec = module.GetFileSpec();36 if (!file_spec.IsValid())37 return std::nullopt;38 39 persistence_data.module_path = GetSBFileSpecPath(file_spec);40 persistence_data.symbol_name = symbol.GetName();41 return persistence_data;42}43 44void Breakpoint::SetCondition() { m_bp.SetCondition(m_condition.c_str()); }45 46void Breakpoint::SetHitCondition() {47 uint64_t hitCount = 0;48 if (llvm::to_integer(m_hit_condition, hitCount))49 m_bp.SetIgnoreCount(hitCount - 1);50}51 52protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() {53 protocol::Breakpoint breakpoint;54 55 // Each breakpoint location is treated as a separate breakpoint for VS code.56 // They don't have the notion of a single breakpoint with multiple locations.57 if (!m_bp.IsValid())58 return breakpoint;59 60 breakpoint.verified = m_bp.GetNumResolvedLocations() > 0;61 breakpoint.id = m_bp.GetID();62 // VS Code DAP doesn't currently allow one breakpoint to have multiple63 // locations so we just report the first one. If we report all locations64 // then the IDE starts showing the wrong line numbers and locations for65 // other source file and line breakpoints in the same file.66 67 // Below we search for the first resolved location in a breakpoint and report68 // this as the breakpoint location since it will have a complete location69 // that is at least loaded in the current process.70 lldb::SBBreakpointLocation bp_loc;71 const auto num_locs = m_bp.GetNumLocations();72 for (size_t i = 0; i < num_locs; ++i) {73 bp_loc = m_bp.GetLocationAtIndex(i);74 if (bp_loc.IsResolved())75 break;76 }77 // If not locations are resolved, use the first location.78 if (!bp_loc.IsResolved())79 bp_loc = m_bp.GetLocationAtIndex(0);80 auto bp_addr = bp_loc.GetAddress();81 82 if (bp_addr.IsValid()) {83 std::string formatted_addr =84 "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget()));85 breakpoint.instructionReference = formatted_addr;86 87 std::optional<protocol::Source> source = m_dap.ResolveSource(bp_addr);88 if (source && !IsAssemblySource(*source)) {89 auto line_entry = bp_addr.GetLineEntry();90 const auto line = line_entry.GetLine();91 if (line != LLDB_INVALID_LINE_NUMBER)92 breakpoint.line = line;93 const auto column = line_entry.GetColumn();94 if (column != LLDB_INVALID_COLUMN_NUMBER)95 breakpoint.column = column;96 } else if (source) {97 // Assembly breakpoint.98 auto symbol = bp_addr.GetSymbol();99 if (symbol.IsValid()) {100 breakpoint.line =101 m_bp.GetTarget()102 .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr)103 .GetSize() +104 1;105 106 // Add persistent data so that the breakpoint can be resolved107 // in future sessions.108 std::optional<protocol::PersistenceData> persistence_data =109 GetPersistenceDataForSymbol(symbol);110 if (persistence_data) {111 source->adapterData =112 protocol::SourceLLDBData{std::move(persistence_data)};113 }114 }115 }116 117 breakpoint.source = std::move(source);118 }119 120 return breakpoint;121}122 123bool Breakpoint::MatchesName(const char *name) {124 return m_bp.MatchesName(name);125}126 127void Breakpoint::SetBreakpoint() {128 lldb::SBMutex lock = m_dap.GetAPIMutex();129 std::lock_guard<lldb::SBMutex> guard(lock);130 131 m_bp.AddName(kDAPBreakpointLabel);132 if (!m_condition.empty())133 SetCondition();134 if (!m_hit_condition.empty())135 SetHitCondition();136}137