130 lines · cpp
1//===-- BreakpointLocationsHandler..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 "DAP.h"10#include "RequestHandler.h"11#include <optional>12#include <vector>13 14namespace lldb_dap {15 16/// The `breakpointLocations` request returns all possible locations for source17/// breakpoints in a given range. Clients should only call this request if the18/// corresponding capability `supportsBreakpointLocationsRequest` is true.19llvm::Expected<protocol::BreakpointLocationsResponseBody>20BreakpointLocationsRequestHandler::Run(21 const protocol::BreakpointLocationsArguments &args) const {22 uint32_t start_line = args.line;23 uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER);24 uint32_t end_line = args.endLine.value_or(start_line);25 uint32_t end_column =26 args.endColumn.value_or(std::numeric_limits<uint32_t>::max());27 28 // Find all relevant lines & columns.29 std::vector<std::pair<uint32_t, uint32_t>> locations;30 if (args.source.sourceReference) {31 locations = GetAssemblyBreakpointLocations(*args.source.sourceReference,32 start_line, end_line);33 } else {34 std::string path = args.source.path.value_or("");35 locations = GetSourceBreakpointLocations(36 std::move(path), start_line, start_column, end_line, end_column);37 }38 39 // The line entries are sorted by addresses, but we must return the list40 // ordered by line / column position.41 std::sort(locations.begin(), locations.end());42 locations.erase(llvm::unique(locations), locations.end());43 44 std::vector<protocol::BreakpointLocation> breakpoint_locations;45 for (auto &l : locations)46 breakpoint_locations.push_back(47 {l.first, l.second, std::nullopt, std::nullopt});48 49 return protocol::BreakpointLocationsResponseBody{50 /*breakpoints=*/std::move(breakpoint_locations)};51}52 53std::vector<std::pair<uint32_t, uint32_t>>54BreakpointLocationsRequestHandler::GetSourceBreakpointLocations(55 std::string path, uint32_t start_line, uint32_t start_column,56 uint32_t end_line, uint32_t end_column) const {57 std::vector<std::pair<uint32_t, uint32_t>> locations;58 lldb::SBFileSpec file_spec(path.c_str(), true);59 lldb::SBSymbolContextList compile_units =60 dap.target.FindCompileUnits(file_spec);61 62 for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit;63 ++c_idx) {64 const lldb::SBCompileUnit &compile_unit =65 compile_units.GetContextAtIndex(c_idx).GetCompileUnit();66 if (!compile_unit.IsValid())67 continue;68 lldb::SBFileSpec primary_file_spec = compile_unit.GetFileSpec();69 70 // Go through the line table and find all matching lines / columns71 for (uint32_t l_idx = 0, l_limit = compile_unit.GetNumLineEntries();72 l_idx < l_limit; ++l_idx) {73 lldb::SBLineEntry line_entry = compile_unit.GetLineEntryAtIndex(l_idx);74 75 // Filter by line / column76 uint32_t line = line_entry.GetLine();77 if (line < start_line || line > end_line)78 continue;79 uint32_t column = line_entry.GetColumn();80 if (column == LLDB_INVALID_COLUMN_NUMBER)81 continue;82 if (line == start_line && column < start_column)83 continue;84 if (line == end_line && column > end_column)85 continue;86 87 // Make sure we are in the right file.88 // We might have a match on line & column range and still89 // be in the wrong file, e.g. for included files.90 // Given that the involved pointers point into LLDB's string pool,91 // we can directly compare the `const char*` pointers.92 if (line_entry.GetFileSpec().GetFilename() !=93 primary_file_spec.GetFilename() ||94 line_entry.GetFileSpec().GetDirectory() !=95 primary_file_spec.GetDirectory())96 continue;97 98 locations.emplace_back(line, column);99 }100 }101 102 return locations;103}104 105std::vector<std::pair<uint32_t, uint32_t>>106BreakpointLocationsRequestHandler::GetAssemblyBreakpointLocations(107 int64_t source_reference, uint32_t start_line, uint32_t end_line) const {108 std::vector<std::pair<uint32_t, uint32_t>> locations;109 lldb::SBAddress address(source_reference, dap.target);110 if (!address.IsValid())111 return locations;112 113 lldb::SBSymbol symbol = address.GetSymbol();114 if (!symbol.IsValid())115 return locations;116 117 // start_line is relative to the symbol's start address.118 lldb::SBInstructionList insts = symbol.GetInstructions(dap.target);119 if (insts.GetSize() > (start_line - 1))120 locations.reserve(insts.GetSize() - (start_line - 1));121 for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1);122 ++i) {123 locations.emplace_back(i, 1);124 }125 126 return locations;127}128 129} // namespace lldb_dap130