blob: 5979130853d6dcaadc1438fe8bf1608bf293da43 [file] [log] [blame]
Johnny Chenf04ee932011-09-22 18:04:58 +00001//===-- CommandObjectWatchpoint.cpp -----------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "CommandObjectWatchpoint.h"
Johnny Chene9a56272012-08-09 23:09:42 +000011#include "CommandObjectWatchpointCommand.h"
Johnny Chenf04ee932011-09-22 18:04:58 +000012
13// C Includes
14// C++ Includes
Eugene Zelenko3f18ea02016-02-24 02:05:55 +000015#include <vector>
16
Johnny Chenf04ee932011-09-22 18:04:58 +000017// Other libraries and framework includes
Eugene Zelenko3f18ea02016-02-24 02:05:55 +000018#include "llvm/ADT/StringRef.h"
19
Johnny Chenf04ee932011-09-22 18:04:58 +000020// Project includes
Johnny Chen01a67862011-10-14 00:42:25 +000021#include "lldb/Breakpoint/Watchpoint.h"
22#include "lldb/Breakpoint/WatchpointList.h"
Johnny Chenf04ee932011-09-22 18:04:58 +000023#include "lldb/Core/StreamString.h"
Johnny Chendedb67a2012-01-30 21:46:17 +000024#include "lldb/Core/ValueObject.h"
25#include "lldb/Core/ValueObjectVariable.h"
Vince Harron5275aaa2015-01-15 20:08:35 +000026#include "lldb/Host/StringConvert.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000027#include "lldb/Interpreter/CommandCompletions.h"
Johnny Chenf04ee932011-09-22 18:04:58 +000028#include "lldb/Interpreter/CommandInterpreter.h"
29#include "lldb/Interpreter/CommandReturnObject.h"
Johnny Chendedb67a2012-01-30 21:46:17 +000030#include "lldb/Symbol/Variable.h"
31#include "lldb/Symbol/VariableList.h"
Zachary Turnera78bd7f2015-03-03 23:11:11 +000032#include "lldb/Target/StackFrame.h"
Johnny Chendedb67a2012-01-30 21:46:17 +000033#include "lldb/Target/Target.h"
Johnny Chenf04ee932011-09-22 18:04:58 +000034
Johnny Chenf04ee932011-09-22 18:04:58 +000035using namespace lldb;
36using namespace lldb_private;
37
Kate Stoneb9c1b512016-09-06 20:57:50 +000038static void AddWatchpointDescription(Stream *s, Watchpoint *wp,
39 lldb::DescriptionLevel level) {
40 s->IndentMore();
41 wp->GetDescription(s, level);
42 s->IndentLess();
43 s->EOL();
Johnny Chenf04ee932011-09-22 18:04:58 +000044}
45
Kate Stoneb9c1b512016-09-06 20:57:50 +000046static bool CheckTargetForWatchpointOperations(Target *target,
47 CommandReturnObject &result) {
48 if (target == nullptr) {
49 result.AppendError("Invalid target. No existing target or watchpoints.");
50 result.SetStatus(eReturnStatusFailed);
51 return false;
52 }
53 bool process_is_valid =
54 target->GetProcessSP() && target->GetProcessSP()->IsAlive();
55 if (!process_is_valid) {
56 result.AppendError("Thre's no process or it is not alive.");
57 result.SetStatus(eReturnStatusFailed);
58 return false;
59 }
60 // Target passes our checks, return true.
61 return true;
Johnny Chenf04ee932011-09-22 18:04:58 +000062}
63
Johnny Chenf04ee932011-09-22 18:04:58 +000064// Equivalent class: {"-", "to", "To", "TO"} of range specifier array.
Kate Stoneb9c1b512016-09-06 20:57:50 +000065static const char *RSA[4] = {"-", "to", "To", "TO"};
Johnny Chenf04ee932011-09-22 18:04:58 +000066
67// Return the index to RSA if found; otherwise -1 is returned.
Zachary Turner97d2c402016-10-05 23:40:23 +000068static int32_t WithRSAIndex(llvm::StringRef Arg) {
Kate Stoneb9c1b512016-09-06 20:57:50 +000069
70 uint32_t i;
71 for (i = 0; i < 4; ++i)
72 if (Arg.find(RSA[i]) != llvm::StringRef::npos)
73 return i;
74 return -1;
Johnny Chenf04ee932011-09-22 18:04:58 +000075}
76
77// Return true if wp_ids is successfully populated with the watch ids.
78// False otherwise.
Kate Stoneb9c1b512016-09-06 20:57:50 +000079bool CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
80 Target *target, Args &args, std::vector<uint32_t> &wp_ids) {
81 // Pre-condition: args.GetArgumentCount() > 0.
82 if (args.GetArgumentCount() == 0) {
83 if (target == nullptr)
84 return false;
85 WatchpointSP watch_sp = target->GetLastCreatedWatchpoint();
86 if (watch_sp) {
87 wp_ids.push_back(watch_sp->GetID());
88 return true;
89 } else
90 return false;
91 }
Johnny Chenf04ee932011-09-22 18:04:58 +000092
Kate Stoneb9c1b512016-09-06 20:57:50 +000093 llvm::StringRef Minus("-");
94 std::vector<llvm::StringRef> StrRefArgs;
Zachary Turner97d2c402016-10-05 23:40:23 +000095 llvm::StringRef first;
96 llvm::StringRef second;
Kate Stoneb9c1b512016-09-06 20:57:50 +000097 size_t i;
98 int32_t idx;
99 // Go through the arguments and make a canonical form of arg list containing
100 // only numbers with possible "-" in between.
Zachary Turner97d2c402016-10-05 23:40:23 +0000101 for (auto &entry : args.entries()) {
102 if ((idx = WithRSAIndex(entry.ref)) == -1) {
103 StrRefArgs.push_back(entry.ref);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000104 continue;
Johnny Chenf04ee932011-09-22 18:04:58 +0000105 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000106 // The Arg contains the range specifier, split it, then.
Zachary Turner97d2c402016-10-05 23:40:23 +0000107 std::tie(first, second) = entry.ref.split(RSA[idx]);
108 if (!first.empty())
109 StrRefArgs.push_back(first);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000110 StrRefArgs.push_back(Minus);
Zachary Turner97d2c402016-10-05 23:40:23 +0000111 if (!second.empty())
112 StrRefArgs.push_back(second);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000113 }
114 // Now process the canonical list and fill in the vector of uint32_t's.
115 // If there is any error, return false and the client should ignore wp_ids.
116 uint32_t beg, end, id;
117 size_t size = StrRefArgs.size();
118 bool in_range = false;
119 for (i = 0; i < size; ++i) {
120 llvm::StringRef Arg = StrRefArgs[i];
121 if (in_range) {
122 // Look for the 'end' of the range. Note StringRef::getAsInteger()
123 // returns true to signify error while parsing.
124 if (Arg.getAsInteger(0, end))
Johnny Chenf04ee932011-09-22 18:04:58 +0000125 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000126 // Found a range! Now append the elements.
127 for (id = beg; id <= end; ++id)
128 wp_ids.push_back(id);
129 in_range = false;
130 continue;
131 }
132 if (i < (size - 1) && StrRefArgs[i + 1] == Minus) {
133 if (Arg.getAsInteger(0, beg))
134 return false;
135 // Turn on the in_range flag, we are looking for end of range next.
136 ++i;
137 in_range = true;
138 continue;
139 }
140 // Otherwise, we have a simple ID. Just append it.
141 if (Arg.getAsInteger(0, beg))
142 return false;
143 wp_ids.push_back(beg);
144 }
145 // It is an error if after the loop, we're still in_range.
146 if (in_range)
147 return false;
Johnny Chenf04ee932011-09-22 18:04:58 +0000148
Kate Stoneb9c1b512016-09-06 20:57:50 +0000149 return true; // Success!
Johnny Chenf04ee932011-09-22 18:04:58 +0000150}
151
152//-------------------------------------------------------------------------
Jim Ingham5a988412012-06-08 21:56:10 +0000153// CommandObjectWatchpointList
154//-------------------------------------------------------------------------
Zachary Turner1f0f5b52016-09-22 20:22:55 +0000155
156//-------------------------------------------------------------------------
157// CommandObjectWatchpointList::Options
158//-------------------------------------------------------------------------
159#pragma mark List::CommandOptions
160
161static OptionDefinition g_watchpoint_list_options[] = {
162 // clang-format off
163 { LLDB_OPT_SET_1, false, "brief", 'b', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Give a brief description of the watchpoint (no location info)." },
164 { LLDB_OPT_SET_2, false, "full", 'f', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Give a full description of the watchpoint and its locations." },
165 { LLDB_OPT_SET_3, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Explain everything we know about the watchpoint (for debugging debugger bugs)." }
166 // clang-format on
167};
168
Jim Ingham5a988412012-06-08 21:56:10 +0000169#pragma mark List
170
Kate Stoneb9c1b512016-09-06 20:57:50 +0000171class CommandObjectWatchpointList : public CommandObjectParsed {
Jim Ingham5a988412012-06-08 21:56:10 +0000172public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000173 CommandObjectWatchpointList(CommandInterpreter &interpreter)
174 : CommandObjectParsed(
175 interpreter, "watchpoint list",
176 "List all watchpoints at configurable levels of detail.", nullptr),
177 m_options() {
178 CommandArgumentEntry arg;
179 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
180 eArgTypeWatchpointIDRange);
181 // Add the entry for the first argument for this command to the object's
182 // arguments vector.
183 m_arguments.push_back(arg);
184 }
185
186 ~CommandObjectWatchpointList() override = default;
187
188 Options *GetOptions() override { return &m_options; }
189
190 class CommandOptions : public Options {
191 public:
192 CommandOptions()
193 : Options(),
194 m_level(lldb::eDescriptionLevelBrief) // Watchpoint List defaults to
195 // brief descriptions
196 {}
197
198 ~CommandOptions() override = default;
199
200 Error SetOptionValue(uint32_t option_idx, const char *option_arg,
201 ExecutionContext *execution_context) override {
202 Error error;
203 const int short_option = m_getopt_table[option_idx].val;
204
205 switch (short_option) {
206 case 'b':
207 m_level = lldb::eDescriptionLevelBrief;
208 break;
209 case 'f':
210 m_level = lldb::eDescriptionLevelFull;
211 break;
212 case 'v':
213 m_level = lldb::eDescriptionLevelVerbose;
214 break;
215 default:
216 error.SetErrorStringWithFormat("unrecognized option '%c'",
217 short_option);
218 break;
219 }
220
221 return error;
Jim Ingham5a988412012-06-08 21:56:10 +0000222 }
223
Kate Stoneb9c1b512016-09-06 20:57:50 +0000224 void OptionParsingStarting(ExecutionContext *execution_context) override {
225 m_level = lldb::eDescriptionLevelFull;
Jim Ingham5a988412012-06-08 21:56:10 +0000226 }
227
Zachary Turner1f0f5b52016-09-22 20:22:55 +0000228 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
Zachary Turner70602432016-09-22 21:06:13 +0000229 return llvm::makeArrayRef(g_watchpoint_list_options);
Zachary Turner1f0f5b52016-09-22 20:22:55 +0000230 }
Jim Ingham5a988412012-06-08 21:56:10 +0000231
Kate Stoneb9c1b512016-09-06 20:57:50 +0000232 // Instance variables to hold the values for command options.
Jim Ingham5a988412012-06-08 21:56:10 +0000233
Kate Stoneb9c1b512016-09-06 20:57:50 +0000234 lldb::DescriptionLevel m_level;
235 };
Jim Ingham5a988412012-06-08 21:56:10 +0000236
237protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000238 bool DoExecute(Args &command, CommandReturnObject &result) override {
239 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
240 if (target == nullptr) {
241 result.AppendError("Invalid target. No current target or watchpoints.");
242 result.SetStatus(eReturnStatusSuccessFinishNoResult);
243 return true;
Jim Ingham5a988412012-06-08 21:56:10 +0000244 }
245
Kate Stoneb9c1b512016-09-06 20:57:50 +0000246 if (target->GetProcessSP() && target->GetProcessSP()->IsAlive()) {
247 uint32_t num_supported_hardware_watchpoints;
248 Error error = target->GetProcessSP()->GetWatchpointSupportInfo(
249 num_supported_hardware_watchpoints);
250 if (error.Success())
251 result.AppendMessageWithFormat(
252 "Number of supported hardware watchpoints: %u\n",
253 num_supported_hardware_watchpoints);
254 }
255
256 const WatchpointList &watchpoints = target->GetWatchpointList();
257
258 std::unique_lock<std::recursive_mutex> lock;
259 target->GetWatchpointList().GetListMutex(lock);
260
261 size_t num_watchpoints = watchpoints.GetSize();
262
263 if (num_watchpoints == 0) {
264 result.AppendMessage("No watchpoints currently set.");
265 result.SetStatus(eReturnStatusSuccessFinishNoResult);
266 return true;
267 }
268
269 Stream &output_stream = result.GetOutputStream();
270
271 if (command.GetArgumentCount() == 0) {
272 // No watchpoint selected; show info about all currently set watchpoints.
273 result.AppendMessage("Current watchpoints:");
274 for (size_t i = 0; i < num_watchpoints; ++i) {
275 Watchpoint *wp = watchpoints.GetByIndex(i).get();
276 AddWatchpointDescription(&output_stream, wp, m_options.m_level);
277 }
278 result.SetStatus(eReturnStatusSuccessFinishNoResult);
279 } else {
280 // Particular watchpoints selected; enable them.
281 std::vector<uint32_t> wp_ids;
282 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
283 target, command, wp_ids)) {
284 result.AppendError("Invalid watchpoints specification.");
285 result.SetStatus(eReturnStatusFailed);
286 return false;
287 }
288
289 const size_t size = wp_ids.size();
290 for (size_t i = 0; i < size; ++i) {
291 Watchpoint *wp = watchpoints.FindByID(wp_ids[i]).get();
292 if (wp)
293 AddWatchpointDescription(&output_stream, wp, m_options.m_level);
294 result.SetStatus(eReturnStatusSuccessFinishNoResult);
295 }
296 }
297
298 return result.Succeeded();
299 }
300
Jim Ingham5a988412012-06-08 21:56:10 +0000301private:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000302 CommandOptions m_options;
Jim Ingham5a988412012-06-08 21:56:10 +0000303};
304
305//-------------------------------------------------------------------------
Jim Ingham5a988412012-06-08 21:56:10 +0000306// CommandObjectWatchpointEnable
307//-------------------------------------------------------------------------
308#pragma mark Enable
309
Kate Stoneb9c1b512016-09-06 20:57:50 +0000310class CommandObjectWatchpointEnable : public CommandObjectParsed {
Jim Ingham5a988412012-06-08 21:56:10 +0000311public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000312 CommandObjectWatchpointEnable(CommandInterpreter &interpreter)
313 : CommandObjectParsed(interpreter, "enable",
314 "Enable the specified disabled watchpoint(s). If "
315 "no watchpoints are specified, enable all of them.",
316 nullptr) {
317 CommandArgumentEntry arg;
318 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
319 eArgTypeWatchpointIDRange);
320 // Add the entry for the first argument for this command to the object's
321 // arguments vector.
322 m_arguments.push_back(arg);
323 }
Jim Ingham5a988412012-06-08 21:56:10 +0000324
Kate Stoneb9c1b512016-09-06 20:57:50 +0000325 ~CommandObjectWatchpointEnable() override = default;
Jim Ingham5a988412012-06-08 21:56:10 +0000326
327protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000328 bool DoExecute(Args &command, CommandReturnObject &result) override {
329 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
330 if (!CheckTargetForWatchpointOperations(target, result))
331 return false;
Jim Ingham5a988412012-06-08 21:56:10 +0000332
Kate Stoneb9c1b512016-09-06 20:57:50 +0000333 std::unique_lock<std::recursive_mutex> lock;
334 target->GetWatchpointList().GetListMutex(lock);
Jim Ingham5a988412012-06-08 21:56:10 +0000335
Kate Stoneb9c1b512016-09-06 20:57:50 +0000336 const WatchpointList &watchpoints = target->GetWatchpointList();
Jim Ingham5a988412012-06-08 21:56:10 +0000337
Kate Stoneb9c1b512016-09-06 20:57:50 +0000338 size_t num_watchpoints = watchpoints.GetSize();
Jim Ingham5a988412012-06-08 21:56:10 +0000339
Kate Stoneb9c1b512016-09-06 20:57:50 +0000340 if (num_watchpoints == 0) {
341 result.AppendError("No watchpoints exist to be enabled.");
342 result.SetStatus(eReturnStatusFailed);
343 return false;
Jim Ingham5a988412012-06-08 21:56:10 +0000344 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000345
346 if (command.GetArgumentCount() == 0) {
347 // No watchpoint selected; enable all currently set watchpoints.
348 target->EnableAllWatchpoints();
349 result.AppendMessageWithFormat("All watchpoints enabled. (%" PRIu64
350 " watchpoints)\n",
351 (uint64_t)num_watchpoints);
352 result.SetStatus(eReturnStatusSuccessFinishNoResult);
353 } else {
354 // Particular watchpoints selected; enable them.
355 std::vector<uint32_t> wp_ids;
356 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
357 target, command, wp_ids)) {
358 result.AppendError("Invalid watchpoints specification.");
359 result.SetStatus(eReturnStatusFailed);
360 return false;
361 }
362
363 int count = 0;
364 const size_t size = wp_ids.size();
365 for (size_t i = 0; i < size; ++i)
366 if (target->EnableWatchpointByID(wp_ids[i]))
367 ++count;
368 result.AppendMessageWithFormat("%d watchpoints enabled.\n", count);
369 result.SetStatus(eReturnStatusSuccessFinishNoResult);
370 }
371
372 return result.Succeeded();
373 }
Jim Ingham5a988412012-06-08 21:56:10 +0000374};
375
376//-------------------------------------------------------------------------
377// CommandObjectWatchpointDisable
378//-------------------------------------------------------------------------
379#pragma mark Disable
380
Kate Stoneb9c1b512016-09-06 20:57:50 +0000381class CommandObjectWatchpointDisable : public CommandObjectParsed {
Jim Ingham5a988412012-06-08 21:56:10 +0000382public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000383 CommandObjectWatchpointDisable(CommandInterpreter &interpreter)
384 : CommandObjectParsed(interpreter, "watchpoint disable",
385 "Disable the specified watchpoint(s) without "
386 "removing it/them. If no watchpoints are "
387 "specified, disable them all.",
388 nullptr) {
389 CommandArgumentEntry arg;
390 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
391 eArgTypeWatchpointIDRange);
392 // Add the entry for the first argument for this command to the object's
393 // arguments vector.
394 m_arguments.push_back(arg);
395 }
Jim Ingham5a988412012-06-08 21:56:10 +0000396
Kate Stoneb9c1b512016-09-06 20:57:50 +0000397 ~CommandObjectWatchpointDisable() override = default;
Jim Ingham5a988412012-06-08 21:56:10 +0000398
399protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000400 bool DoExecute(Args &command, CommandReturnObject &result) override {
401 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
402 if (!CheckTargetForWatchpointOperations(target, result))
403 return false;
Jim Ingham5a988412012-06-08 21:56:10 +0000404
Kate Stoneb9c1b512016-09-06 20:57:50 +0000405 std::unique_lock<std::recursive_mutex> lock;
406 target->GetWatchpointList().GetListMutex(lock);
Jim Ingham5a988412012-06-08 21:56:10 +0000407
Kate Stoneb9c1b512016-09-06 20:57:50 +0000408 const WatchpointList &watchpoints = target->GetWatchpointList();
409 size_t num_watchpoints = watchpoints.GetSize();
Jim Ingham5a988412012-06-08 21:56:10 +0000410
Kate Stoneb9c1b512016-09-06 20:57:50 +0000411 if (num_watchpoints == 0) {
412 result.AppendError("No watchpoints exist to be disabled.");
413 result.SetStatus(eReturnStatusFailed);
414 return false;
Jim Ingham5a988412012-06-08 21:56:10 +0000415 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000416
417 if (command.GetArgumentCount() == 0) {
418 // No watchpoint selected; disable all currently set watchpoints.
419 if (target->DisableAllWatchpoints()) {
420 result.AppendMessageWithFormat("All watchpoints disabled. (%" PRIu64
421 " watchpoints)\n",
422 (uint64_t)num_watchpoints);
423 result.SetStatus(eReturnStatusSuccessFinishNoResult);
424 } else {
425 result.AppendError("Disable all watchpoints failed\n");
426 result.SetStatus(eReturnStatusFailed);
427 }
428 } else {
429 // Particular watchpoints selected; disable them.
430 std::vector<uint32_t> wp_ids;
431 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
432 target, command, wp_ids)) {
433 result.AppendError("Invalid watchpoints specification.");
434 result.SetStatus(eReturnStatusFailed);
435 return false;
436 }
437
438 int count = 0;
439 const size_t size = wp_ids.size();
440 for (size_t i = 0; i < size; ++i)
441 if (target->DisableWatchpointByID(wp_ids[i]))
442 ++count;
443 result.AppendMessageWithFormat("%d watchpoints disabled.\n", count);
444 result.SetStatus(eReturnStatusSuccessFinishNoResult);
445 }
446
447 return result.Succeeded();
448 }
Jim Ingham5a988412012-06-08 21:56:10 +0000449};
450
451//-------------------------------------------------------------------------
452// CommandObjectWatchpointDelete
453//-------------------------------------------------------------------------
454#pragma mark Delete
455
Kate Stoneb9c1b512016-09-06 20:57:50 +0000456class CommandObjectWatchpointDelete : public CommandObjectParsed {
Jim Ingham5a988412012-06-08 21:56:10 +0000457public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000458 CommandObjectWatchpointDelete(CommandInterpreter &interpreter)
459 : CommandObjectParsed(interpreter, "watchpoint delete",
460 "Delete the specified watchpoint(s). If no "
461 "watchpoints are specified, delete them all.",
462 nullptr) {
463 CommandArgumentEntry arg;
464 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
465 eArgTypeWatchpointIDRange);
466 // Add the entry for the first argument for this command to the object's
467 // arguments vector.
468 m_arguments.push_back(arg);
469 }
Jim Ingham5a988412012-06-08 21:56:10 +0000470
Kate Stoneb9c1b512016-09-06 20:57:50 +0000471 ~CommandObjectWatchpointDelete() override = default;
Jim Ingham5a988412012-06-08 21:56:10 +0000472
473protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000474 bool DoExecute(Args &command, CommandReturnObject &result) override {
475 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
476 if (!CheckTargetForWatchpointOperations(target, result))
477 return false;
Jim Ingham5a988412012-06-08 21:56:10 +0000478
Kate Stoneb9c1b512016-09-06 20:57:50 +0000479 std::unique_lock<std::recursive_mutex> lock;
480 target->GetWatchpointList().GetListMutex(lock);
Saleem Abdulrasoolbb19a132016-05-19 05:13:57 +0000481
Kate Stoneb9c1b512016-09-06 20:57:50 +0000482 const WatchpointList &watchpoints = target->GetWatchpointList();
Jim Ingham5a988412012-06-08 21:56:10 +0000483
Kate Stoneb9c1b512016-09-06 20:57:50 +0000484 size_t num_watchpoints = watchpoints.GetSize();
Jim Ingham5a988412012-06-08 21:56:10 +0000485
Kate Stoneb9c1b512016-09-06 20:57:50 +0000486 if (num_watchpoints == 0) {
487 result.AppendError("No watchpoints exist to be deleted.");
488 result.SetStatus(eReturnStatusFailed);
489 return false;
Jim Ingham5a988412012-06-08 21:56:10 +0000490 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000491
492 if (command.GetArgumentCount() == 0) {
493 if (!m_interpreter.Confirm(
494 "About to delete all watchpoints, do you want to do that?",
495 true)) {
496 result.AppendMessage("Operation cancelled...");
497 } else {
498 target->RemoveAllWatchpoints();
499 result.AppendMessageWithFormat("All watchpoints removed. (%" PRIu64
500 " watchpoints)\n",
501 (uint64_t)num_watchpoints);
502 }
503 result.SetStatus(eReturnStatusSuccessFinishNoResult);
504 } else {
505 // Particular watchpoints selected; delete them.
506 std::vector<uint32_t> wp_ids;
507 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
508 target, command, wp_ids)) {
509 result.AppendError("Invalid watchpoints specification.");
510 result.SetStatus(eReturnStatusFailed);
511 return false;
512 }
513
514 int count = 0;
515 const size_t size = wp_ids.size();
516 for (size_t i = 0; i < size; ++i)
517 if (target->RemoveWatchpointByID(wp_ids[i]))
518 ++count;
519 result.AppendMessageWithFormat("%d watchpoints deleted.\n", count);
520 result.SetStatus(eReturnStatusSuccessFinishNoResult);
521 }
522
523 return result.Succeeded();
524 }
Jim Ingham5a988412012-06-08 21:56:10 +0000525};
526
527//-------------------------------------------------------------------------
528// CommandObjectWatchpointIgnore
529//-------------------------------------------------------------------------
530
Zachary Turner1f0f5b52016-09-22 20:22:55 +0000531#pragma mark Ignore::CommandOptions
532static OptionDefinition g_watchpoint_ignore_options[] = {
533 // clang-format off
534 { LLDB_OPT_SET_ALL, true, "ignore-count", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "Set the number of times this watchpoint is skipped before stopping." }
535 // clang-format on
536};
537
Kate Stoneb9c1b512016-09-06 20:57:50 +0000538class CommandObjectWatchpointIgnore : public CommandObjectParsed {
Jim Ingham5a988412012-06-08 21:56:10 +0000539public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000540 CommandObjectWatchpointIgnore(CommandInterpreter &interpreter)
541 : CommandObjectParsed(interpreter, "watchpoint ignore",
542 "Set ignore count on the specified watchpoint(s). "
543 "If no watchpoints are specified, set them all.",
Eugene Zelenko3f18ea02016-02-24 02:05:55 +0000544 nullptr),
Kate Stoneb9c1b512016-09-06 20:57:50 +0000545 m_options() {
546 CommandArgumentEntry arg;
547 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
548 eArgTypeWatchpointIDRange);
549 // Add the entry for the first argument for this command to the object's
550 // arguments vector.
551 m_arguments.push_back(arg);
552 }
553
554 ~CommandObjectWatchpointIgnore() override = default;
555
556 Options *GetOptions() override { return &m_options; }
557
558 class CommandOptions : public Options {
559 public:
560 CommandOptions() : Options(), m_ignore_count(0) {}
561
562 ~CommandOptions() override = default;
563
564 Error SetOptionValue(uint32_t option_idx, const char *option_arg,
565 ExecutionContext *execution_context) override {
566 Error error;
567 const int short_option = m_getopt_table[option_idx].val;
568
569 switch (short_option) {
570 case 'i':
571 m_ignore_count = StringConvert::ToUInt32(option_arg, UINT32_MAX, 0);
572 if (m_ignore_count == UINT32_MAX)
573 error.SetErrorStringWithFormat("invalid ignore count '%s'",
574 option_arg);
575 break;
576 default:
577 error.SetErrorStringWithFormat("unrecognized option '%c'",
578 short_option);
579 break;
580 }
581
582 return error;
Jim Ingham5a988412012-06-08 21:56:10 +0000583 }
584
Kate Stoneb9c1b512016-09-06 20:57:50 +0000585 void OptionParsingStarting(ExecutionContext *execution_context) override {
586 m_ignore_count = 0;
Jim Ingham5a988412012-06-08 21:56:10 +0000587 }
588
Zachary Turner1f0f5b52016-09-22 20:22:55 +0000589 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
Zachary Turner70602432016-09-22 21:06:13 +0000590 return llvm::makeArrayRef(g_watchpoint_ignore_options);
Zachary Turner1f0f5b52016-09-22 20:22:55 +0000591 }
Jim Ingham5a988412012-06-08 21:56:10 +0000592
Kate Stoneb9c1b512016-09-06 20:57:50 +0000593 // Instance variables to hold the values for command options.
Jim Ingham5a988412012-06-08 21:56:10 +0000594
Kate Stoneb9c1b512016-09-06 20:57:50 +0000595 uint32_t m_ignore_count;
596 };
Jim Ingham5a988412012-06-08 21:56:10 +0000597
598protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000599 bool DoExecute(Args &command, CommandReturnObject &result) override {
600 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
601 if (!CheckTargetForWatchpointOperations(target, result))
602 return false;
Jim Ingham5a988412012-06-08 21:56:10 +0000603
Kate Stoneb9c1b512016-09-06 20:57:50 +0000604 std::unique_lock<std::recursive_mutex> lock;
605 target->GetWatchpointList().GetListMutex(lock);
Saleem Abdulrasoolbb19a132016-05-19 05:13:57 +0000606
Kate Stoneb9c1b512016-09-06 20:57:50 +0000607 const WatchpointList &watchpoints = target->GetWatchpointList();
Jim Ingham5a988412012-06-08 21:56:10 +0000608
Kate Stoneb9c1b512016-09-06 20:57:50 +0000609 size_t num_watchpoints = watchpoints.GetSize();
Jim Ingham5a988412012-06-08 21:56:10 +0000610
Kate Stoneb9c1b512016-09-06 20:57:50 +0000611 if (num_watchpoints == 0) {
612 result.AppendError("No watchpoints exist to be ignored.");
613 result.SetStatus(eReturnStatusFailed);
614 return false;
Jim Ingham5a988412012-06-08 21:56:10 +0000615 }
616
Kate Stoneb9c1b512016-09-06 20:57:50 +0000617 if (command.GetArgumentCount() == 0) {
618 target->IgnoreAllWatchpoints(m_options.m_ignore_count);
619 result.AppendMessageWithFormat("All watchpoints ignored. (%" PRIu64
620 " watchpoints)\n",
621 (uint64_t)num_watchpoints);
622 result.SetStatus(eReturnStatusSuccessFinishNoResult);
623 } else {
624 // Particular watchpoints selected; ignore them.
625 std::vector<uint32_t> wp_ids;
626 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
627 target, command, wp_ids)) {
628 result.AppendError("Invalid watchpoints specification.");
629 result.SetStatus(eReturnStatusFailed);
630 return false;
631 }
632
633 int count = 0;
634 const size_t size = wp_ids.size();
635 for (size_t i = 0; i < size; ++i)
636 if (target->IgnoreWatchpointByID(wp_ids[i], m_options.m_ignore_count))
637 ++count;
638 result.AppendMessageWithFormat("%d watchpoints ignored.\n", count);
639 result.SetStatus(eReturnStatusSuccessFinishNoResult);
640 }
641
642 return result.Succeeded();
643 }
644
Jim Ingham5a988412012-06-08 21:56:10 +0000645private:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000646 CommandOptions m_options;
Jim Ingham5a988412012-06-08 21:56:10 +0000647};
648
Jim Ingham5a988412012-06-08 21:56:10 +0000649//-------------------------------------------------------------------------
650// CommandObjectWatchpointModify
651//-------------------------------------------------------------------------
Zachary Turner1f0f5b52016-09-22 20:22:55 +0000652
653#pragma mark Modify::CommandOptions
654
655static OptionDefinition g_watchpoint_modify_options[] = {
656 // clang-format off
657 { LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpression, "The watchpoint stops only if this condition expression evaluates to true." }
658 // clang-format on
659};
660
Jim Ingham5a988412012-06-08 21:56:10 +0000661#pragma mark Modify
662
Kate Stoneb9c1b512016-09-06 20:57:50 +0000663class CommandObjectWatchpointModify : public CommandObjectParsed {
Jim Ingham5a988412012-06-08 21:56:10 +0000664public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000665 CommandObjectWatchpointModify(CommandInterpreter &interpreter)
666 : CommandObjectParsed(
667 interpreter, "watchpoint modify",
668 "Modify the options on a watchpoint or set of watchpoints in the "
669 "executable. "
670 "If no watchpoint is specified, act on the last created "
671 "watchpoint. "
672 "Passing an empty argument clears the modification.",
673 nullptr),
674 m_options() {
675 CommandArgumentEntry arg;
676 CommandObject::AddIDsArgumentData(arg, eArgTypeWatchpointID,
677 eArgTypeWatchpointIDRange);
678 // Add the entry for the first argument for this command to the object's
679 // arguments vector.
680 m_arguments.push_back(arg);
681 }
682
683 ~CommandObjectWatchpointModify() override = default;
684
685 Options *GetOptions() override { return &m_options; }
686
687 class CommandOptions : public Options {
688 public:
689 CommandOptions() : Options(), m_condition(), m_condition_passed(false) {}
690
691 ~CommandOptions() override = default;
692
693 Error SetOptionValue(uint32_t option_idx, const char *option_arg,
694 ExecutionContext *execution_context) override {
695 Error error;
696 const int short_option = m_getopt_table[option_idx].val;
697
698 switch (short_option) {
699 case 'c':
700 if (option_arg != nullptr)
701 m_condition.assign(option_arg);
702 else
703 m_condition.clear();
704 m_condition_passed = true;
705 break;
706 default:
707 error.SetErrorStringWithFormat("unrecognized option '%c'",
708 short_option);
709 break;
710 }
711
712 return error;
Jim Ingham5a988412012-06-08 21:56:10 +0000713 }
714
Kate Stoneb9c1b512016-09-06 20:57:50 +0000715 void OptionParsingStarting(ExecutionContext *execution_context) override {
716 m_condition.clear();
717 m_condition_passed = false;
Jim Ingham5a988412012-06-08 21:56:10 +0000718 }
719
Zachary Turner1f0f5b52016-09-22 20:22:55 +0000720 llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
Zachary Turner70602432016-09-22 21:06:13 +0000721 return llvm::makeArrayRef(g_watchpoint_modify_options);
Zachary Turner1f0f5b52016-09-22 20:22:55 +0000722 }
Jim Ingham5a988412012-06-08 21:56:10 +0000723
Kate Stoneb9c1b512016-09-06 20:57:50 +0000724 // Instance variables to hold the values for command options.
Jim Ingham5a988412012-06-08 21:56:10 +0000725
Kate Stoneb9c1b512016-09-06 20:57:50 +0000726 std::string m_condition;
727 bool m_condition_passed;
728 };
Jim Ingham5a988412012-06-08 21:56:10 +0000729
730protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000731 bool DoExecute(Args &command, CommandReturnObject &result) override {
732 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
733 if (!CheckTargetForWatchpointOperations(target, result))
734 return false;
Jim Ingham5a988412012-06-08 21:56:10 +0000735
Kate Stoneb9c1b512016-09-06 20:57:50 +0000736 std::unique_lock<std::recursive_mutex> lock;
737 target->GetWatchpointList().GetListMutex(lock);
Saleem Abdulrasoolbb19a132016-05-19 05:13:57 +0000738
Kate Stoneb9c1b512016-09-06 20:57:50 +0000739 const WatchpointList &watchpoints = target->GetWatchpointList();
Jim Ingham5a988412012-06-08 21:56:10 +0000740
Kate Stoneb9c1b512016-09-06 20:57:50 +0000741 size_t num_watchpoints = watchpoints.GetSize();
Jim Ingham5a988412012-06-08 21:56:10 +0000742
Kate Stoneb9c1b512016-09-06 20:57:50 +0000743 if (num_watchpoints == 0) {
744 result.AppendError("No watchpoints exist to be modified.");
745 result.SetStatus(eReturnStatusFailed);
746 return false;
Jim Ingham5a988412012-06-08 21:56:10 +0000747 }
748
Kate Stoneb9c1b512016-09-06 20:57:50 +0000749 if (command.GetArgumentCount() == 0) {
750 WatchpointSP wp_sp = target->GetLastCreatedWatchpoint();
751 wp_sp->SetCondition(m_options.m_condition.c_str());
752 result.SetStatus(eReturnStatusSuccessFinishNoResult);
753 } else {
754 // Particular watchpoints selected; set condition on them.
755 std::vector<uint32_t> wp_ids;
756 if (!CommandObjectMultiwordWatchpoint::VerifyWatchpointIDs(
757 target, command, wp_ids)) {
758 result.AppendError("Invalid watchpoints specification.");
759 result.SetStatus(eReturnStatusFailed);
760 return false;
761 }
762
763 int count = 0;
764 const size_t size = wp_ids.size();
765 for (size_t i = 0; i < size; ++i) {
766 WatchpointSP wp_sp = watchpoints.FindByID(wp_ids[i]);
767 if (wp_sp) {
768 wp_sp->SetCondition(m_options.m_condition.c_str());
769 ++count;
770 }
771 }
772 result.AppendMessageWithFormat("%d watchpoints modified.\n", count);
773 result.SetStatus(eReturnStatusSuccessFinishNoResult);
774 }
775
776 return result.Succeeded();
777 }
778
Jim Ingham5a988412012-06-08 21:56:10 +0000779private:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000780 CommandOptions m_options;
Jim Ingham5a988412012-06-08 21:56:10 +0000781};
782
Jim Ingham5a988412012-06-08 21:56:10 +0000783//-------------------------------------------------------------------------
784// CommandObjectWatchpointSetVariable
785//-------------------------------------------------------------------------
786#pragma mark SetVariable
787
Kate Stoneb9c1b512016-09-06 20:57:50 +0000788class CommandObjectWatchpointSetVariable : public CommandObjectParsed {
Jim Ingham5a988412012-06-08 21:56:10 +0000789public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000790 CommandObjectWatchpointSetVariable(CommandInterpreter &interpreter)
791 : CommandObjectParsed(
792 interpreter, "watchpoint set variable",
793 "Set a watchpoint on a variable. "
794 "Use the '-w' option to specify the type of watchpoint and "
795 "the '-s' option to specify the byte size to watch for. "
796 "If no '-w' option is specified, it defaults to write. "
797 "If no '-s' option is specified, it defaults to the variable's "
798 "byte size. "
799 "Note that there are limited hardware resources for watchpoints. "
800 "If watchpoint setting fails, consider disable/delete existing "
801 "ones "
802 "to free up resources.",
803 nullptr,
804 eCommandRequiresFrame | eCommandTryTargetAPILock |
805 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
806 m_option_group(), m_option_watchpoint() {
807 SetHelpLong(
808 R"(
Kate Stoneea671fb2015-07-14 05:48:36 +0000809Examples:
810
811(lldb) watchpoint set variable -w read_write my_global_var
812
Kate Stoneb9c1b512016-09-06 20:57:50 +0000813)"
814 " Watches my_global_var for read/write access, with the region to watch \
815corresponding to the byte size of the data type.");
Jim Ingham5a988412012-06-08 21:56:10 +0000816
Kate Stoneb9c1b512016-09-06 20:57:50 +0000817 CommandArgumentEntry arg;
818 CommandArgumentData var_name_arg;
Jim Ingham5a988412012-06-08 21:56:10 +0000819
Kate Stoneb9c1b512016-09-06 20:57:50 +0000820 // Define the only variant of this arg.
821 var_name_arg.arg_type = eArgTypeVarName;
822 var_name_arg.arg_repetition = eArgRepeatPlain;
Jim Ingham5a988412012-06-08 21:56:10 +0000823
Kate Stoneb9c1b512016-09-06 20:57:50 +0000824 // Push the variant into the argument entry.
825 arg.push_back(var_name_arg);
Jim Ingham5a988412012-06-08 21:56:10 +0000826
Kate Stoneb9c1b512016-09-06 20:57:50 +0000827 // Push the data for the only argument into the m_arguments vector.
828 m_arguments.push_back(arg);
Jim Ingham5a988412012-06-08 21:56:10 +0000829
Kate Stoneb9c1b512016-09-06 20:57:50 +0000830 // Absorb the '-w' and '-s' options into our option group.
831 m_option_group.Append(&m_option_watchpoint, LLDB_OPT_SET_ALL,
832 LLDB_OPT_SET_1);
833 m_option_group.Finalize();
834 }
835
836 ~CommandObjectWatchpointSetVariable() override = default;
837
838 Options *GetOptions() override { return &m_option_group; }
Jim Ingham5a988412012-06-08 21:56:10 +0000839
840protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000841 static size_t GetVariableCallback(void *baton, const char *name,
842 VariableList &variable_list) {
843 Target *target = static_cast<Target *>(baton);
844 if (target) {
845 return target->GetImages().FindGlobalVariables(ConstString(name), true,
846 UINT32_MAX, variable_list);
Sean Callanan903259f2012-09-14 17:20:18 +0000847 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000848 return 0;
849 }
Jim Ingham5a988412012-06-08 21:56:10 +0000850
Kate Stoneb9c1b512016-09-06 20:57:50 +0000851 bool DoExecute(Args &command, CommandReturnObject &result) override {
852 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
853 StackFrame *frame = m_exe_ctx.GetFramePtr();
Jim Ingham5a988412012-06-08 21:56:10 +0000854
Kate Stoneb9c1b512016-09-06 20:57:50 +0000855 // If no argument is present, issue an error message. There's no way to set
856 // a watchpoint.
857 if (command.GetArgumentCount() <= 0) {
858 result.GetErrorStream().Printf("error: required argument missing; "
859 "specify your program variable to watch "
860 "for\n");
861 result.SetStatus(eReturnStatusFailed);
862 return false;
Jim Ingham5a988412012-06-08 21:56:10 +0000863 }
864
Kate Stoneb9c1b512016-09-06 20:57:50 +0000865 // If no '-w' is specified, default to '-w write'.
866 if (!m_option_watchpoint.watch_type_specified) {
867 m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
868 }
869
870 // We passed the sanity check for the command.
871 // Proceed to set the watchpoint now.
872 lldb::addr_t addr = 0;
873 size_t size = 0;
874
875 VariableSP var_sp;
876 ValueObjectSP valobj_sp;
877 Stream &output_stream = result.GetOutputStream();
878
879 // A simple watch variable gesture allows only one argument.
880 if (command.GetArgumentCount() != 1) {
881 result.GetErrorStream().Printf(
882 "error: specify exactly one variable to watch for\n");
883 result.SetStatus(eReturnStatusFailed);
884 return false;
885 }
886
887 // Things have checked out ok...
888 Error error;
889 uint32_t expr_path_options =
890 StackFrame::eExpressionPathOptionCheckPtrVsMember |
891 StackFrame::eExpressionPathOptionsAllowDirectIVarAccess;
892 valobj_sp = frame->GetValueForVariableExpressionPath(
893 command.GetArgumentAtIndex(0), eNoDynamicValues, expr_path_options,
894 var_sp, error);
895
896 if (!valobj_sp) {
897 // Not in the frame; let's check the globals.
898
899 VariableList variable_list;
900 ValueObjectList valobj_list;
901
902 Error error(Variable::GetValuesForVariableExpressionPath(
903 command.GetArgumentAtIndex(0),
904 m_exe_ctx.GetBestExecutionContextScope(), GetVariableCallback, target,
905 variable_list, valobj_list));
906
907 if (valobj_list.GetSize())
908 valobj_sp = valobj_list.GetValueObjectAtIndex(0);
909 }
910
911 CompilerType compiler_type;
912
913 if (valobj_sp) {
914 AddressType addr_type;
915 addr = valobj_sp->GetAddressOf(false, &addr_type);
916 if (addr_type == eAddressTypeLoad) {
917 // We're in business.
918 // Find out the size of this variable.
919 size = m_option_watchpoint.watch_size == 0
920 ? valobj_sp->GetByteSize()
921 : m_option_watchpoint.watch_size;
922 }
923 compiler_type = valobj_sp->GetCompilerType();
924 } else {
925 const char *error_cstr = error.AsCString(nullptr);
926 if (error_cstr)
927 result.GetErrorStream().Printf("error: %s\n", error_cstr);
928 else
929 result.GetErrorStream().Printf("error: unable to find any variable "
930 "expression path that matches '%s'\n",
931 command.GetArgumentAtIndex(0));
932 return false;
933 }
934
935 // Now it's time to create the watchpoint.
936 uint32_t watch_type = m_option_watchpoint.watch_type;
937
938 error.Clear();
939 Watchpoint *wp =
940 target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error)
941 .get();
942 if (wp) {
943 wp->SetWatchSpec(command.GetArgumentAtIndex(0));
944 wp->SetWatchVariable(true);
945 if (var_sp && var_sp->GetDeclaration().GetFile()) {
946 StreamString ss;
947 // True to show fullpath for declaration file.
948 var_sp->GetDeclaration().DumpStopContext(&ss, true);
949 wp->SetDeclInfo(ss.GetString());
950 }
951 output_stream.Printf("Watchpoint created: ");
952 wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
953 output_stream.EOL();
954 result.SetStatus(eReturnStatusSuccessFinishResult);
955 } else {
956 result.AppendErrorWithFormat(
957 "Watchpoint creation failed (addr=0x%" PRIx64 ", size=%" PRIu64
958 ", variable expression='%s').\n",
959 addr, (uint64_t)size, command.GetArgumentAtIndex(0));
960 if (error.AsCString(nullptr))
961 result.AppendError(error.AsCString());
962 result.SetStatus(eReturnStatusFailed);
963 }
964
965 return result.Succeeded();
966 }
967
Jim Ingham5a988412012-06-08 21:56:10 +0000968private:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000969 OptionGroupOptions m_option_group;
970 OptionGroupWatchpoint m_option_watchpoint;
Jim Ingham5a988412012-06-08 21:56:10 +0000971};
972
973//-------------------------------------------------------------------------
974// CommandObjectWatchpointSetExpression
975//-------------------------------------------------------------------------
976#pragma mark Set
977
Kate Stoneb9c1b512016-09-06 20:57:50 +0000978class CommandObjectWatchpointSetExpression : public CommandObjectRaw {
Jim Ingham5a988412012-06-08 21:56:10 +0000979public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000980 CommandObjectWatchpointSetExpression(CommandInterpreter &interpreter)
981 : CommandObjectRaw(
982 interpreter, "watchpoint set expression",
983 "Set a watchpoint on an address by supplying an expression. "
984 "Use the '-w' option to specify the type of watchpoint and "
985 "the '-s' option to specify the byte size to watch for. "
986 "If no '-w' option is specified, it defaults to write. "
987 "If no '-s' option is specified, it defaults to the target's "
988 "pointer byte size. "
989 "Note that there are limited hardware resources for watchpoints. "
990 "If watchpoint setting fails, consider disable/delete existing "
991 "ones "
992 "to free up resources.",
Zachary Turnera4496982016-10-05 21:14:38 +0000993 "",
Kate Stoneb9c1b512016-09-06 20:57:50 +0000994 eCommandRequiresFrame | eCommandTryTargetAPILock |
995 eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
996 m_option_group(), m_option_watchpoint() {
997 SetHelpLong(
998 R"(
Kate Stoneea671fb2015-07-14 05:48:36 +0000999Examples:
1000
Stephane Sezer6944f0e2016-04-05 17:30:31 +00001001(lldb) watchpoint set expression -w write -s 1 -- foo + 32
Kate Stoneea671fb2015-07-14 05:48:36 +00001002
Kate Stoneb9c1b512016-09-06 20:57:50 +00001003 Watches write access for the 1-byte region pointed to by the address 'foo + 32')");
Jim Ingham5a988412012-06-08 21:56:10 +00001004
Kate Stoneb9c1b512016-09-06 20:57:50 +00001005 CommandArgumentEntry arg;
1006 CommandArgumentData expression_arg;
Jim Ingham5a988412012-06-08 21:56:10 +00001007
Kate Stoneb9c1b512016-09-06 20:57:50 +00001008 // Define the only variant of this arg.
1009 expression_arg.arg_type = eArgTypeExpression;
1010 expression_arg.arg_repetition = eArgRepeatPlain;
Jim Ingham5a988412012-06-08 21:56:10 +00001011
Kate Stoneb9c1b512016-09-06 20:57:50 +00001012 // Push the only variant into the argument entry.
1013 arg.push_back(expression_arg);
Jim Ingham5a988412012-06-08 21:56:10 +00001014
Kate Stoneb9c1b512016-09-06 20:57:50 +00001015 // Push the data for the only argument into the m_arguments vector.
1016 m_arguments.push_back(arg);
Jim Ingham5a988412012-06-08 21:56:10 +00001017
Kate Stoneb9c1b512016-09-06 20:57:50 +00001018 // Absorb the '-w' and '-s' options into our option group.
1019 m_option_group.Append(&m_option_watchpoint, LLDB_OPT_SET_ALL,
1020 LLDB_OPT_SET_1);
1021 m_option_group.Finalize();
1022 }
Jim Ingham5a988412012-06-08 21:56:10 +00001023
Kate Stoneb9c1b512016-09-06 20:57:50 +00001024 ~CommandObjectWatchpointSetExpression() override = default;
1025
1026 // Overrides base class's behavior where WantsCompletion =
1027 // !WantsRawCommandString.
1028 bool WantsCompletion() override { return true; }
1029
1030 Options *GetOptions() override { return &m_option_group; }
Jim Ingham5a988412012-06-08 21:56:10 +00001031
1032protected:
Kate Stoneb9c1b512016-09-06 20:57:50 +00001033 bool DoExecute(const char *raw_command,
1034 CommandReturnObject &result) override {
1035 auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
1036 m_option_group.NotifyOptionParsingStarting(
1037 &exe_ctx); // This is a raw command, so notify the option group
Jim Ingham5a988412012-06-08 21:56:10 +00001038
Kate Stoneb9c1b512016-09-06 20:57:50 +00001039 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
1040 StackFrame *frame = m_exe_ctx.GetFramePtr();
1041
1042 Args command(raw_command);
1043 const char *expr = nullptr;
1044 if (raw_command[0] == '-') {
1045 // We have some options and these options MUST end with --.
1046 const char *end_options = nullptr;
1047 const char *s = raw_command;
1048 while (s && s[0]) {
1049 end_options = ::strstr(s, "--");
1050 if (end_options) {
1051 end_options += 2; // Get past the "--"
1052 if (::isspace(end_options[0])) {
1053 expr = end_options;
1054 while (::isspace(*expr))
1055 ++expr;
1056 break;
1057 }
Greg Clayton25d59412013-02-14 04:15:23 +00001058 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001059 s = end_options;
1060 }
Jim Ingham5a988412012-06-08 21:56:10 +00001061
Kate Stoneb9c1b512016-09-06 20:57:50 +00001062 if (end_options) {
1063 Args args(llvm::StringRef(raw_command, end_options - raw_command));
1064 if (!ParseOptions(args, result))
1065 return false;
Jim Ingham5a988412012-06-08 21:56:10 +00001066
Kate Stoneb9c1b512016-09-06 20:57:50 +00001067 Error error(m_option_group.NotifyOptionParsingFinished(&exe_ctx));
1068 if (error.Fail()) {
1069 result.AppendError(error.AsCString());
1070 result.SetStatus(eReturnStatusFailed);
1071 return false;
Jim Ingham5a988412012-06-08 21:56:10 +00001072 }
Kate Stoneb9c1b512016-09-06 20:57:50 +00001073 }
Jim Ingham5a988412012-06-08 21:56:10 +00001074 }
1075
Kate Stoneb9c1b512016-09-06 20:57:50 +00001076 if (expr == nullptr)
1077 expr = raw_command;
1078
1079 // If no argument is present, issue an error message. There's no way to set
1080 // a watchpoint.
1081 if (command.GetArgumentCount() == 0) {
1082 result.GetErrorStream().Printf("error: required argument missing; "
1083 "specify an expression to evaulate into "
1084 "the address to watch for\n");
1085 result.SetStatus(eReturnStatusFailed);
1086 return false;
1087 }
1088
1089 // If no '-w' is specified, default to '-w write'.
1090 if (!m_option_watchpoint.watch_type_specified) {
1091 m_option_watchpoint.watch_type = OptionGroupWatchpoint::eWatchWrite;
1092 }
1093
1094 // We passed the sanity check for the command.
1095 // Proceed to set the watchpoint now.
1096 lldb::addr_t addr = 0;
1097 size_t size = 0;
1098
1099 ValueObjectSP valobj_sp;
1100
1101 // Use expression evaluation to arrive at the address to watch.
1102 EvaluateExpressionOptions options;
1103 options.SetCoerceToId(false);
1104 options.SetUnwindOnError(true);
1105 options.SetKeepInMemory(false);
1106 options.SetTryAllThreads(true);
1107 options.SetTimeoutUsec(0);
1108
1109 ExpressionResults expr_result =
1110 target->EvaluateExpression(expr, frame, valobj_sp, options);
1111 if (expr_result != eExpressionCompleted) {
1112 result.GetErrorStream().Printf(
1113 "error: expression evaluation of address to watch failed\n");
1114 result.GetErrorStream().Printf("expression evaluated: %s\n", expr);
1115 result.SetStatus(eReturnStatusFailed);
1116 return false;
1117 }
1118
1119 // Get the address to watch.
1120 bool success = false;
1121 addr = valobj_sp->GetValueAsUnsigned(0, &success);
1122 if (!success) {
1123 result.GetErrorStream().Printf(
1124 "error: expression did not evaluate to an address\n");
1125 result.SetStatus(eReturnStatusFailed);
1126 return false;
1127 }
1128
1129 if (m_option_watchpoint.watch_size != 0)
1130 size = m_option_watchpoint.watch_size;
1131 else
1132 size = target->GetArchitecture().GetAddressByteSize();
1133
1134 // Now it's time to create the watchpoint.
1135 uint32_t watch_type = m_option_watchpoint.watch_type;
1136
1137 // Fetch the type from the value object, the type of the watched object is
1138 // the pointee type
1139 /// of the expression, so convert to that if we found a valid type.
1140 CompilerType compiler_type(valobj_sp->GetCompilerType());
1141
1142 Error error;
1143 Watchpoint *wp =
1144 target->CreateWatchpoint(addr, size, &compiler_type, watch_type, error)
1145 .get();
1146 if (wp) {
1147 Stream &output_stream = result.GetOutputStream();
1148 output_stream.Printf("Watchpoint created: ");
1149 wp->GetDescription(&output_stream, lldb::eDescriptionLevelFull);
1150 output_stream.EOL();
1151 result.SetStatus(eReturnStatusSuccessFinishResult);
1152 } else {
1153 result.AppendErrorWithFormat("Watchpoint creation failed (addr=0x%" PRIx64
1154 ", size=%" PRIu64 ").\n",
1155 addr, (uint64_t)size);
1156 if (error.AsCString(nullptr))
1157 result.AppendError(error.AsCString());
1158 result.SetStatus(eReturnStatusFailed);
1159 }
1160
1161 return result.Succeeded();
1162 }
1163
Jim Ingham5a988412012-06-08 21:56:10 +00001164private:
Kate Stoneb9c1b512016-09-06 20:57:50 +00001165 OptionGroupOptions m_option_group;
1166 OptionGroupWatchpoint m_option_watchpoint;
Jim Ingham5a988412012-06-08 21:56:10 +00001167};
1168
1169//-------------------------------------------------------------------------
1170// CommandObjectWatchpointSet
1171//-------------------------------------------------------------------------
1172#pragma mark Set
1173
Kate Stoneb9c1b512016-09-06 20:57:50 +00001174class CommandObjectWatchpointSet : public CommandObjectMultiword {
Jim Ingham5a988412012-06-08 21:56:10 +00001175public:
Kate Stoneb9c1b512016-09-06 20:57:50 +00001176 CommandObjectWatchpointSet(CommandInterpreter &interpreter)
1177 : CommandObjectMultiword(
1178 interpreter, "watchpoint set", "Commands for setting a watchpoint.",
1179 "watchpoint set <subcommand> [<subcommand-options>]") {
Jim Ingham5a988412012-06-08 21:56:10 +00001180
Kate Stoneb9c1b512016-09-06 20:57:50 +00001181 LoadSubCommand(
1182 "variable",
1183 CommandObjectSP(new CommandObjectWatchpointSetVariable(interpreter)));
1184 LoadSubCommand(
1185 "expression",
1186 CommandObjectSP(new CommandObjectWatchpointSetExpression(interpreter)));
1187 }
1188
1189 ~CommandObjectWatchpointSet() override = default;
Jim Ingham5a988412012-06-08 21:56:10 +00001190};
1191
1192//-------------------------------------------------------------------------
Johnny Chenf04ee932011-09-22 18:04:58 +00001193// CommandObjectMultiwordWatchpoint
1194//-------------------------------------------------------------------------
1195#pragma mark MultiwordWatchpoint
1196
Kate Stoneb9c1b512016-09-06 20:57:50 +00001197CommandObjectMultiwordWatchpoint::CommandObjectMultiwordWatchpoint(
1198 CommandInterpreter &interpreter)
1199 : CommandObjectMultiword(interpreter, "watchpoint",
1200 "Commands for operating on watchpoints.",
1201 "watchpoint <subcommand> [<command-options>]") {
1202 CommandObjectSP list_command_object(
1203 new CommandObjectWatchpointList(interpreter));
1204 CommandObjectSP enable_command_object(
1205 new CommandObjectWatchpointEnable(interpreter));
1206 CommandObjectSP disable_command_object(
1207 new CommandObjectWatchpointDisable(interpreter));
1208 CommandObjectSP delete_command_object(
1209 new CommandObjectWatchpointDelete(interpreter));
1210 CommandObjectSP ignore_command_object(
1211 new CommandObjectWatchpointIgnore(interpreter));
1212 CommandObjectSP command_command_object(
1213 new CommandObjectWatchpointCommand(interpreter));
1214 CommandObjectSP modify_command_object(
1215 new CommandObjectWatchpointModify(interpreter));
1216 CommandObjectSP set_command_object(
1217 new CommandObjectWatchpointSet(interpreter));
Johnny Chenf04ee932011-09-22 18:04:58 +00001218
Kate Stoneb9c1b512016-09-06 20:57:50 +00001219 list_command_object->SetCommandName("watchpoint list");
1220 enable_command_object->SetCommandName("watchpoint enable");
1221 disable_command_object->SetCommandName("watchpoint disable");
1222 delete_command_object->SetCommandName("watchpoint delete");
1223 ignore_command_object->SetCommandName("watchpoint ignore");
1224 command_command_object->SetCommandName("watchpoint command");
1225 modify_command_object->SetCommandName("watchpoint modify");
1226 set_command_object->SetCommandName("watchpoint set");
Johnny Chenf04ee932011-09-22 18:04:58 +00001227
Kate Stoneb9c1b512016-09-06 20:57:50 +00001228 LoadSubCommand("list", list_command_object);
1229 LoadSubCommand("enable", enable_command_object);
1230 LoadSubCommand("disable", disable_command_object);
1231 LoadSubCommand("delete", delete_command_object);
1232 LoadSubCommand("ignore", ignore_command_object);
1233 LoadSubCommand("command", command_command_object);
1234 LoadSubCommand("modify", modify_command_object);
1235 LoadSubCommand("set", set_command_object);
Johnny Chenf04ee932011-09-22 18:04:58 +00001236}
1237
Eugene Zelenko3f18ea02016-02-24 02:05:55 +00001238CommandObjectMultiwordWatchpoint::~CommandObjectMultiwordWatchpoint() = default;