Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Breakpoint/BreakpointResolver.cpp
39587 views
1
//===-- BreakpointResolver.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-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "lldb/Breakpoint/BreakpointResolver.h"
10
11
#include "lldb/Breakpoint/Breakpoint.h"
12
#include "lldb/Breakpoint/BreakpointLocation.h"
13
// Have to include the other breakpoint resolver types here so the static
14
// create from StructuredData can call them.
15
#include "lldb/Breakpoint/BreakpointResolverAddress.h"
16
#include "lldb/Breakpoint/BreakpointResolverFileLine.h"
17
#include "lldb/Breakpoint/BreakpointResolverFileRegex.h"
18
#include "lldb/Breakpoint/BreakpointResolverName.h"
19
#include "lldb/Breakpoint/BreakpointResolverScripted.h"
20
#include "lldb/Core/Address.h"
21
#include "lldb/Core/ModuleList.h"
22
#include "lldb/Core/SearchFilter.h"
23
#include "lldb/Symbol/CompileUnit.h"
24
#include "lldb/Symbol/Function.h"
25
#include "lldb/Symbol/SymbolContext.h"
26
#include "lldb/Target/Language.h"
27
#include "lldb/Target/Target.h"
28
#include "lldb/Utility/LLDBLog.h"
29
#include "lldb/Utility/Log.h"
30
#include "lldb/Utility/Stream.h"
31
#include "lldb/Utility/StreamString.h"
32
#include <optional>
33
34
using namespace lldb_private;
35
using namespace lldb;
36
37
// BreakpointResolver:
38
const char *BreakpointResolver::g_ty_to_name[] = {"FileAndLine", "Address",
39
"SymbolName", "SourceRegex",
40
"Python", "Exception",
41
"Unknown"};
42
43
const char *BreakpointResolver::g_option_names[static_cast<uint32_t>(
44
BreakpointResolver::OptionNames::LastOptionName)] = {
45
"AddressOffset", "Exact", "FileName", "Inlines", "Language",
46
"LineNumber", "Column", "ModuleName", "NameMask", "Offset",
47
"PythonClass", "Regex", "ScriptArgs", "SectionName", "SearchDepth",
48
"SkipPrologue", "SymbolNames"};
49
50
const char *BreakpointResolver::ResolverTyToName(enum ResolverTy type) {
51
if (type > LastKnownResolverType)
52
return g_ty_to_name[UnknownResolver];
53
54
return g_ty_to_name[type];
55
}
56
57
BreakpointResolver::ResolverTy
58
BreakpointResolver::NameToResolverTy(llvm::StringRef name) {
59
for (size_t i = 0; i < LastKnownResolverType; i++) {
60
if (name == g_ty_to_name[i])
61
return (ResolverTy)i;
62
}
63
return UnknownResolver;
64
}
65
66
BreakpointResolver::BreakpointResolver(const BreakpointSP &bkpt,
67
const unsigned char resolverTy,
68
lldb::addr_t offset)
69
: m_breakpoint(bkpt), m_offset(offset), SubclassID(resolverTy) {}
70
71
BreakpointResolver::~BreakpointResolver() = default;
72
73
BreakpointResolverSP BreakpointResolver::CreateFromStructuredData(
74
const StructuredData::Dictionary &resolver_dict, Status &error) {
75
BreakpointResolverSP result_sp;
76
if (!resolver_dict.IsValid()) {
77
error.SetErrorString("Can't deserialize from an invalid data object.");
78
return result_sp;
79
}
80
81
llvm::StringRef subclass_name;
82
83
bool success = resolver_dict.GetValueForKeyAsString(
84
GetSerializationSubclassKey(), subclass_name);
85
86
if (!success) {
87
error.SetErrorString("Resolver data missing subclass resolver key");
88
return result_sp;
89
}
90
91
ResolverTy resolver_type = NameToResolverTy(subclass_name);
92
if (resolver_type == UnknownResolver) {
93
error.SetErrorStringWithFormatv("Unknown resolver type: {0}.",
94
subclass_name);
95
return result_sp;
96
}
97
98
StructuredData::Dictionary *subclass_options = nullptr;
99
success = resolver_dict.GetValueForKeyAsDictionary(
100
GetSerializationSubclassOptionsKey(), subclass_options);
101
if (!success || !subclass_options || !subclass_options->IsValid()) {
102
error.SetErrorString("Resolver data missing subclass options key.");
103
return result_sp;
104
}
105
106
lldb::offset_t offset;
107
success = subclass_options->GetValueForKeyAsInteger(
108
GetKey(OptionNames::Offset), offset);
109
if (!success) {
110
error.SetErrorString("Resolver data missing offset options key.");
111
return result_sp;
112
}
113
114
switch (resolver_type) {
115
case FileLineResolver:
116
result_sp = BreakpointResolverFileLine::CreateFromStructuredData(
117
*subclass_options, error);
118
break;
119
case AddressResolver:
120
result_sp = BreakpointResolverAddress::CreateFromStructuredData(
121
*subclass_options, error);
122
break;
123
case NameResolver:
124
result_sp = BreakpointResolverName::CreateFromStructuredData(
125
*subclass_options, error);
126
break;
127
case FileRegexResolver:
128
result_sp = BreakpointResolverFileRegex::CreateFromStructuredData(
129
*subclass_options, error);
130
break;
131
case PythonResolver:
132
result_sp = BreakpointResolverScripted::CreateFromStructuredData(
133
*subclass_options, error);
134
break;
135
case ExceptionResolver:
136
error.SetErrorString("Exception resolvers are hard.");
137
break;
138
default:
139
llvm_unreachable("Should never get an unresolvable resolver type.");
140
}
141
142
if (error.Fail() || !result_sp)
143
return {};
144
145
// Add on the global offset option:
146
result_sp->SetOffset(offset);
147
return result_sp;
148
}
149
150
StructuredData::DictionarySP BreakpointResolver::WrapOptionsDict(
151
StructuredData::DictionarySP options_dict_sp) {
152
if (!options_dict_sp || !options_dict_sp->IsValid())
153
return StructuredData::DictionarySP();
154
155
StructuredData::DictionarySP type_dict_sp(new StructuredData::Dictionary());
156
type_dict_sp->AddStringItem(GetSerializationSubclassKey(), GetResolverName());
157
type_dict_sp->AddItem(GetSerializationSubclassOptionsKey(), options_dict_sp);
158
159
// Add the m_offset to the dictionary:
160
options_dict_sp->AddIntegerItem(GetKey(OptionNames::Offset), m_offset);
161
162
return type_dict_sp;
163
}
164
165
void BreakpointResolver::SetBreakpoint(const BreakpointSP &bkpt) {
166
assert(bkpt);
167
m_breakpoint = bkpt;
168
NotifyBreakpointSet();
169
}
170
171
void BreakpointResolver::ResolveBreakpointInModules(SearchFilter &filter,
172
ModuleList &modules) {
173
filter.SearchInModuleList(*this, modules);
174
}
175
176
void BreakpointResolver::ResolveBreakpoint(SearchFilter &filter) {
177
filter.Search(*this);
178
}
179
180
namespace {
181
struct SourceLoc {
182
uint32_t line = UINT32_MAX;
183
uint16_t column;
184
SourceLoc(uint32_t l, std::optional<uint16_t> c)
185
: line(l), column(c ? *c : LLDB_INVALID_COLUMN_NUMBER) {}
186
SourceLoc(const SymbolContext &sc)
187
: line(sc.line_entry.line),
188
column(sc.line_entry.column ? sc.line_entry.column
189
: LLDB_INVALID_COLUMN_NUMBER) {}
190
};
191
192
bool operator<(const SourceLoc lhs, const SourceLoc rhs) {
193
if (lhs.line < rhs.line)
194
return true;
195
if (lhs.line > rhs.line)
196
return false;
197
// uint32_t a_col = lhs.column ? lhs.column : LLDB_INVALID_COLUMN_NUMBER;
198
// uint32_t b_col = rhs.column ? rhs.column : LLDB_INVALID_COLUMN_NUMBER;
199
return lhs.column < rhs.column;
200
}
201
} // namespace
202
203
void BreakpointResolver::SetSCMatchesByLine(
204
SearchFilter &filter, SymbolContextList &sc_list, bool skip_prologue,
205
llvm::StringRef log_ident, uint32_t line, std::optional<uint16_t> column) {
206
llvm::SmallVector<SymbolContext, 16> all_scs;
207
208
for (const auto &sc : sc_list) {
209
if (Language::GetGlobalLanguageProperties()
210
.GetEnableFilterForLineBreakpoints())
211
if (Language *lang = Language::FindPlugin(sc.GetLanguage());
212
lang && lang->IgnoreForLineBreakpoints(sc))
213
continue;
214
all_scs.push_back(sc);
215
}
216
217
while (all_scs.size()) {
218
uint32_t closest_line = UINT32_MAX;
219
220
// Move all the elements with a matching file spec to the end.
221
auto &match = all_scs[0];
222
auto worklist_begin = std::partition(
223
all_scs.begin(), all_scs.end(), [&](const SymbolContext &sc) {
224
if (sc.line_entry.GetFile() == match.line_entry.GetFile() ||
225
sc.line_entry.original_file_sp->Equal(
226
*match.line_entry.original_file_sp,
227
SupportFile::eEqualFileSpecAndChecksumIfSet)) {
228
// When a match is found, keep track of the smallest line number.
229
closest_line = std::min(closest_line, sc.line_entry.line);
230
return false;
231
}
232
return true;
233
});
234
235
// (worklist_begin, worklist_end) now contains all entries for one filespec.
236
auto worklist_end = all_scs.end();
237
238
if (column) {
239
// If a column was requested, do a more precise match and only
240
// return the first location that comes before or at the
241
// requested location.
242
SourceLoc requested(line, *column);
243
// First, filter out all entries left of the requested column.
244
worklist_end = std::remove_if(
245
worklist_begin, worklist_end,
246
[&](const SymbolContext &sc) { return requested < SourceLoc(sc); });
247
// Sort the remaining entries by (line, column).
248
llvm::sort(worklist_begin, worklist_end,
249
[](const SymbolContext &a, const SymbolContext &b) {
250
return SourceLoc(a) < SourceLoc(b);
251
});
252
253
// Filter out all locations with a source location after the closest match.
254
if (worklist_begin != worklist_end)
255
worklist_end = std::remove_if(
256
worklist_begin, worklist_end, [&](const SymbolContext &sc) {
257
return SourceLoc(*worklist_begin) < SourceLoc(sc);
258
});
259
} else {
260
// Remove all entries with a larger line number.
261
// ResolveSymbolContext will always return a number that is >=
262
// the line number you pass in. So the smaller line number is
263
// always better.
264
worklist_end = std::remove_if(worklist_begin, worklist_end,
265
[&](const SymbolContext &sc) {
266
return closest_line != sc.line_entry.line;
267
});
268
}
269
270
// Sort by file address.
271
llvm::sort(worklist_begin, worklist_end,
272
[](const SymbolContext &a, const SymbolContext &b) {
273
return a.line_entry.range.GetBaseAddress().GetFileAddress() <
274
b.line_entry.range.GetBaseAddress().GetFileAddress();
275
});
276
277
// Go through and see if there are line table entries that are
278
// contiguous, and if so keep only the first of the contiguous range.
279
// We do this by picking the first location in each lexical block.
280
llvm::SmallDenseSet<Block *, 8> blocks_with_breakpoints;
281
for (auto first = worklist_begin; first != worklist_end; ++first) {
282
assert(!blocks_with_breakpoints.count(first->block));
283
blocks_with_breakpoints.insert(first->block);
284
worklist_end =
285
std::remove_if(std::next(first), worklist_end,
286
[&](const SymbolContext &sc) {
287
return blocks_with_breakpoints.count(sc.block);
288
});
289
}
290
291
// Make breakpoints out of the closest line number match.
292
for (auto &sc : llvm::make_range(worklist_begin, worklist_end))
293
AddLocation(filter, sc, skip_prologue, log_ident);
294
295
// Remove all contexts processed by this iteration.
296
all_scs.erase(worklist_begin, all_scs.end());
297
}
298
}
299
300
void BreakpointResolver::AddLocation(SearchFilter &filter,
301
const SymbolContext &sc,
302
bool skip_prologue,
303
llvm::StringRef log_ident) {
304
Log *log = GetLog(LLDBLog::Breakpoints);
305
Address line_start = sc.line_entry.range.GetBaseAddress();
306
if (!line_start.IsValid()) {
307
LLDB_LOGF(log,
308
"error: Unable to set breakpoint %s at file address "
309
"0x%" PRIx64 "\n",
310
log_ident.str().c_str(), line_start.GetFileAddress());
311
return;
312
}
313
314
if (!filter.AddressPasses(line_start)) {
315
LLDB_LOGF(log,
316
"Breakpoint %s at file address 0x%" PRIx64
317
" didn't pass the filter.\n",
318
log_ident.str().c_str(), line_start.GetFileAddress());
319
}
320
321
// If the line number is before the prologue end, move it there...
322
bool skipped_prologue = false;
323
if (skip_prologue && sc.function) {
324
Address prologue_addr(sc.function->GetAddressRange().GetBaseAddress());
325
if (prologue_addr.IsValid() && (line_start == prologue_addr)) {
326
const uint32_t prologue_byte_size = sc.function->GetPrologueByteSize();
327
if (prologue_byte_size) {
328
prologue_addr.Slide(prologue_byte_size);
329
330
if (filter.AddressPasses(prologue_addr)) {
331
skipped_prologue = true;
332
line_start = prologue_addr;
333
}
334
}
335
}
336
}
337
338
BreakpointLocationSP bp_loc_sp(AddLocation(line_start));
339
if (log && bp_loc_sp && !GetBreakpoint()->IsInternal()) {
340
StreamString s;
341
bp_loc_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
342
LLDB_LOGF(log, "Added location (skipped prologue: %s): %s \n",
343
skipped_prologue ? "yes" : "no", s.GetData());
344
}
345
}
346
347
BreakpointLocationSP BreakpointResolver::AddLocation(Address loc_addr,
348
bool *new_location) {
349
loc_addr.Slide(m_offset);
350
return GetBreakpoint()->AddLocation(loc_addr, new_location);
351
}
352
353
void BreakpointResolver::SetOffset(lldb::addr_t offset) {
354
// There may already be an offset, so we are actually adjusting location
355
// addresses by the difference.
356
// lldb::addr_t slide = offset - m_offset;
357
// FIXME: We should go fix up all the already set locations for the new
358
// slide.
359
360
m_offset = offset;
361
}
362
363