Skip to content

Commit 09471f1

Browse files
DavidSpickettjasonmolenda
authored andcommitted
Reland "[lldb] Add 'modify' type watchpoints, make it default (llvm#66308)"
This reverts commit a7b78ca. With updates to the tests. TestWatchTaggedAddress.py: Updated the expected watchpoint types, though I'm not sure there should be a differnt default for the two ways of setting them, that needs to be confirmed. TestStepOverWatchpoint.py: Skipped this everywhere because I think what used to happen is you couldn't put 2 watchpoints on the same address (after alignment). I guess that this is now allowed because modify watchpoints aren't accounted for, but likely should be. Needs investigating. (cherry picked from commit 75e8620)
1 parent 9e36e91 commit 09471f1

File tree

34 files changed

+397
-63
lines changed

34 files changed

+397
-63
lines changed

lldb/bindings/headers.swig

+1
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,5 @@
7777
#include "lldb/API/SBValueList.h"
7878
#include "lldb/API/SBVariablesOptions.h"
7979
#include "lldb/API/SBWatchpoint.h"
80+
#include "lldb/API/SBWatchpointOptions.h"
8081
%}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
%feature("docstring",
2+
"A container for options to use when creating watchpoints."
3+
) lldb::SBWatchpointOptions;
4+
5+
%feature("docstring", "Sets whether the watchpoint should stop on read accesses."
6+
) lldb::SBWatchpointOptions::SetWatchpointTypeRead;
7+
%feature("docstring", "Gets whether the watchpoint should stop on read accesses."
8+
) lldb::SBWatchpointOptions::GetWatchpointTypeRead;
9+
%feature("docstring", "Sets whether the watchpoint should stop on write accesses. eWatchpointWriteTypeOnModify is the most commonly useful mode, where lldb will stop when the watched value has changed. eWatchpointWriteTypeAlways will stop on any write to the watched region, even if it's the value is the same."
10+
) lldb::SBWatchpointOptions::SetWatchpointTypeWrite;
11+
%feature("docstring", "Gets whether the watchpoint should stop on write accesses, returning WatchpointWriteType to indicate the type of write watching that is enabled, or eWatchpointWriteTypeDisabled."
12+
) lldb::SBWatchpointOptions::GetWatchpointTypeWrite;

lldb/bindings/interfaces.swig

+2
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
%include "./interface/SBValueListDocstrings.i"
8181
%include "./interface/SBVariablesOptionsDocstrings.i"
8282
%include "./interface/SBWatchpointDocstrings.i"
83+
%include "./interface/SBWatchpointOptionsDocstrings.i"
8384

8485
/* API headers */
8586
%include "lldb/API/SBAddress.h"
@@ -152,6 +153,7 @@
152153
%include "lldb/API/SBValueList.h"
153154
%include "lldb/API/SBVariablesOptions.h"
154155
%include "lldb/API/SBWatchpoint.h"
156+
%include "lldb/API/SBWatchpointOptions.h"
155157

156158
/* Extensions for SB classes */
157159
%include "./interface/SBAddressExtensions.i"

lldb/include/lldb/API/SBTarget.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "lldb/API/SBType.h"
2222
#include "lldb/API/SBValue.h"
2323
#include "lldb/API/SBWatchpoint.h"
24+
#include "lldb/API/SBWatchpointOptions.h"
2425

2526
namespace lldb_private {
2627
namespace python {
@@ -839,8 +840,13 @@ class LLDB_API SBTarget {
839840

840841
lldb::SBWatchpoint FindWatchpointByID(lldb::watch_id_t watch_id);
841842

843+
LLDB_DEPRECATED("WatchAddress deprecated, use WatchpointCreateByAddress")
842844
lldb::SBWatchpoint WatchAddress(lldb::addr_t addr, size_t size, bool read,
843-
bool write, SBError &error);
845+
bool modify, SBError &error);
846+
847+
lldb::SBWatchpoint
848+
WatchpointCreateByAddress(lldb::addr_t addr, size_t size,
849+
lldb::SBWatchpointOptions options, SBError &error);
844850

845851
bool EnableAllWatchpoints();
846852

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//===-- SBWatchpointOptions.h -----------------------------------*- C++ -*-===//
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+
#ifndef LLDB_API_SBWATCHPOINTOPTIONS_H
10+
#define LLDB_API_SBWATCHPOINTOPTIONS_H
11+
12+
#include "lldb/API/SBDefines.h"
13+
14+
class WatchpointOptionsImpl;
15+
16+
namespace lldb {
17+
18+
class LLDB_API SBWatchpointOptions {
19+
public:
20+
SBWatchpointOptions();
21+
22+
SBWatchpointOptions(const lldb::SBWatchpointOptions &rhs);
23+
24+
~SBWatchpointOptions();
25+
26+
const SBWatchpointOptions &operator=(const lldb::SBWatchpointOptions &rhs);
27+
28+
/// Stop when the watched memory region is read.
29+
void SetWatchpointTypeRead(bool read);
30+
bool GetWatchpointTypeRead() const;
31+
32+
/// Stop when the watched memory region is written to/modified
33+
void SetWatchpointTypeWrite(lldb::WatchpointWriteType write_type);
34+
lldb::WatchpointWriteType GetWatchpointTypeWrite() const;
35+
36+
private:
37+
// This auto_pointer is made in the constructor and is always valid.
38+
mutable std::unique_ptr<WatchpointOptionsImpl> m_opaque_up;
39+
};
40+
41+
} // namespace lldb
42+
43+
#endif // LLDB_API_SBWATCHPOINTOPTIONS_H

lldb/include/lldb/Breakpoint/Watchpoint.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,14 @@ class Watchpoint : public std::enable_shared_from_this<Watchpoint>,
7676

7777
bool WatchpointRead() const;
7878
bool WatchpointWrite() const;
79+
bool WatchpointModify() const;
7980
uint32_t GetIgnoreCount() const;
8081
void SetIgnoreCount(uint32_t n);
8182
void SetWatchpointType(uint32_t type, bool notify = true);
8283
void SetDeclInfo(const std::string &str);
8384
std::string GetWatchSpec();
8485
void SetWatchSpec(const std::string &str);
86+
bool WatchedValueReportable(const ExecutionContext &exe_ctx);
8587

8688
// Snapshot management interface.
8789
bool IsWatchVariable() const;
@@ -212,7 +214,8 @@ class Watchpoint : public std::enable_shared_from_this<Watchpoint>,
212214
// again, we check the count, if it is more than 1, it means the user-
213215
// supplied actions actually want the watchpoint to be disabled!
214216
uint32_t m_watch_read : 1, // 1 if we stop when the watched data is read from
215-
m_watch_write : 1; // 1 if we stop when the watched data is written to
217+
m_watch_write : 1, // 1 if we stop when the watched data is written to
218+
m_watch_modify : 1; // 1 if we stop when the watched data is changed
216219
uint32_t m_ignore_count; // Number of times to ignore this watchpoint
217220
std::string m_decl_str; // Declaration information, if any.
218221
std::string m_watch_spec_str; // Spec for the watchpoint.

lldb/include/lldb/Interpreter/OptionGroupWatchpoint.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@ class OptionGroupWatchpoint : public OptionGroup {
3030

3131
void OptionParsingStarting(ExecutionContext *execution_context) override;
3232

33-
// Note:
34-
// eWatchRead == LLDB_WATCH_TYPE_READ; and
35-
// eWatchWrite == LLDB_WATCH_TYPE_WRITE
33+
/// eWatchRead == LLDB_WATCH_TYPE_READ
34+
/// eWatchWrite == LLDB_WATCH_TYPE_WRITE
35+
/// eWatchModify == LLDB_WATCH_TYPE_MODIFY
36+
/// eWatchReadWrite == LLDB_WATCH_TYPE_READ | LLDB_WATCH_TYPE_WRITE
3637
enum WatchType {
3738
eWatchInvalid = 0,
3839
eWatchRead,
3940
eWatchWrite,
41+
eWatchModify,
4042
eWatchReadWrite
4143
};
4244

lldb/include/lldb/lldb-defines.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@
4444
#define LLDB_WATCH_ID_IS_VALID(uid) ((uid) != (LLDB_INVALID_WATCH_ID))
4545
#define LLDB_WATCH_TYPE_READ (1u << 0)
4646
#define LLDB_WATCH_TYPE_WRITE (1u << 1)
47+
#define LLDB_WATCH_TYPE_MODIFY (1u << 2)
4748
#define LLDB_WATCH_TYPE_IS_VALID(type) \
48-
((type & LLDB_WATCH_TYPE_READ) || (type & LLDB_WATCH_TYPE_WRITE))
49+
((type & LLDB_WATCH_TYPE_READ) || (type & LLDB_WATCH_TYPE_WRITE) || \
50+
(type & LLDB_WATCH_TYPE_MODIFY))
4951

5052
// Generic Register Numbers
5153
#define LLDB_REGNUM_GENERIC_PC 0 // Program Counter

lldb/include/lldb/lldb-enumerations.h

+15
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,21 @@ FLAGS_ENUM(WatchpointEventType){
431431
eWatchpointEventTypeThreadChanged = (1u << 11),
432432
eWatchpointEventTypeTypeChanged = (1u << 12)};
433433

434+
enum WatchpointWriteType {
435+
/// Don't stop when the watched memory region is written to.
436+
eWatchpointWriteTypeDisabled,
437+
/// Stop on any write access to the memory region, even if
438+
/// the value doesn't change. On some architectures, a write
439+
/// near the memory region may be falsely reported as a match,
440+
/// and notify this spurious stop as a watchpoint trap.
441+
eWatchpointWriteTypeAlways,
442+
/// Stop on a write to the memory region that changes its value.
443+
/// This is most likely the behavior a user expects, and is the
444+
/// behavior in gdb. lldb can silently ignore writes near the
445+
/// watched memory region that are reported as accesses to lldb.
446+
eWatchpointWriteTypeOnModify
447+
};
448+
434449
/// Programming language type.
435450
///
436451
/// These enumerations use the same language enumerations as the DWARF

lldb/include/lldb/lldb-forward.h

+1
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ class VariableList;
286286
class Watchpoint;
287287
class WatchpointList;
288288
class WatchpointOptions;
289+
class WatchpointSetOptions;
289290
struct CompilerContext;
290291
struct LineEntry;
291292
struct PropertyDefinition;

lldb/source/API/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ add_lldb_library(liblldb SHARED ${option_framework}
101101
SBValueList.cpp
102102
SBVariablesOptions.cpp
103103
SBWatchpoint.cpp
104+
SBWatchpointOptions.cpp
104105
SBUnixSignals.cpp
105106
SystemInitializerFull.cpp
106107
${lldb_python_wrapper}

lldb/source/API/SBTarget.cpp

+26-14
Original file line numberDiff line numberDiff line change
@@ -1358,27 +1358,39 @@ SBWatchpoint SBTarget::FindWatchpointByID(lldb::watch_id_t wp_id) {
13581358
}
13591359

13601360
lldb::SBWatchpoint SBTarget::WatchAddress(lldb::addr_t addr, size_t size,
1361-
bool read, bool write,
1361+
bool read, bool modify,
13621362
SBError &error) {
13631363
LLDB_INSTRUMENT_VA(this, addr, size, read, write, error);
13641364

1365+
SBWatchpointOptions options;
1366+
options.SetWatchpointTypeRead(read);
1367+
options.SetWatchpointTypeWrite(eWatchpointWriteTypeOnModify);
1368+
return WatchpointCreateByAddress(addr, size, options, error);
1369+
}
1370+
1371+
lldb::SBWatchpoint
1372+
SBTarget::WatchpointCreateByAddress(lldb::addr_t addr, size_t size,
1373+
SBWatchpointOptions options,
1374+
SBError &error) {
1375+
LLDB_INSTRUMENT_VA(this, addr, size, options, error);
1376+
13651377
SBWatchpoint sb_watchpoint;
13661378
lldb::WatchpointSP watchpoint_sp;
13671379
TargetSP target_sp(GetSP());
1368-
if (target_sp && (read || write) && addr != LLDB_INVALID_ADDRESS &&
1369-
size > 0) {
1380+
uint32_t watch_type = 0;
1381+
if (options.GetWatchpointTypeRead())
1382+
watch_type |= LLDB_WATCH_TYPE_READ;
1383+
if (options.GetWatchpointTypeWrite() == eWatchpointWriteTypeAlways)
1384+
watch_type |= LLDB_WATCH_TYPE_WRITE;
1385+
if (options.GetWatchpointTypeWrite() == eWatchpointWriteTypeOnModify)
1386+
watch_type |= LLDB_WATCH_TYPE_MODIFY;
1387+
if (watch_type == 0) {
1388+
error.SetErrorString("Can't create a watchpoint that is neither read nor "
1389+
"write nor modify.");
1390+
return sb_watchpoint;
1391+
}
1392+
if (target_sp && addr != LLDB_INVALID_ADDRESS && size > 0) {
13701393
std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
1371-
uint32_t watch_type = 0;
1372-
if (read)
1373-
watch_type |= LLDB_WATCH_TYPE_READ;
1374-
if (write)
1375-
watch_type |= LLDB_WATCH_TYPE_WRITE;
1376-
if (watch_type == 0) {
1377-
error.SetErrorString(
1378-
"Can't create a watchpoint that is neither read nor write.");
1379-
return sb_watchpoint;
1380-
}
1381-
13821394
// Target::CreateWatchpoint() is thread safe.
13831395
Status cw_error;
13841396
// This API doesn't take in a type, so we can't figure out what it is.

lldb/source/API/SBValue.cpp

+10-3
Original file line numberDiff line numberDiff line change
@@ -1434,10 +1434,17 @@ lldb::SBWatchpoint SBValue::Watch(bool resolve_location, bool read, bool write,
14341434
return sb_watchpoint;
14351435

14361436
uint32_t watch_type = 0;
1437-
if (read)
1437+
if (read) {
14381438
watch_type |= LLDB_WATCH_TYPE_READ;
1439-
if (write)
1440-
watch_type |= LLDB_WATCH_TYPE_WRITE;
1439+
// read + write, the most likely intention
1440+
// is to catch all writes to this, not just
1441+
// value modifications.
1442+
if (write)
1443+
watch_type |= LLDB_WATCH_TYPE_WRITE;
1444+
} else {
1445+
if (write)
1446+
watch_type |= LLDB_WATCH_TYPE_MODIFY;
1447+
}
14411448

14421449
Status rc;
14431450
CompilerType type(value_sp->GetCompilerType());

lldb/source/API/SBWatchpoint.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,8 @@ bool SBWatchpoint::IsWatchingWrites() {
355355
std::lock_guard<std::recursive_mutex> guard(
356356
watchpoint_sp->GetTarget().GetAPIMutex());
357357

358-
return watchpoint_sp->WatchpointWrite();
358+
return watchpoint_sp->WatchpointWrite() ||
359+
watchpoint_sp->WatchpointModify();
359360
}
360361

361362
return false;
+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//===-- SBWatchpointOptions.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/API/SBWatchpointOptions.h"
10+
#include "lldb/Breakpoint/Watchpoint.h"
11+
#include "lldb/Utility/Instrumentation.h"
12+
13+
#include "Utils.h"
14+
15+
using namespace lldb;
16+
using namespace lldb_private;
17+
18+
class WatchpointOptionsImpl {
19+
public:
20+
bool m_read = false;
21+
bool m_write = false;
22+
bool m_modify = false;
23+
};
24+
25+
26+
SBWatchpointOptions::SBWatchpointOptions()
27+
: m_opaque_up(new WatchpointOptionsImpl()) {
28+
LLDB_INSTRUMENT_VA(this);
29+
}
30+
31+
SBWatchpointOptions::SBWatchpointOptions(const SBWatchpointOptions &rhs) {
32+
LLDB_INSTRUMENT_VA(this, rhs);
33+
34+
m_opaque_up = clone(rhs.m_opaque_up);
35+
}
36+
37+
const SBWatchpointOptions &
38+
SBWatchpointOptions::operator=(const SBWatchpointOptions &rhs) {
39+
LLDB_INSTRUMENT_VA(this, rhs);
40+
41+
if (this != &rhs)
42+
m_opaque_up = clone(rhs.m_opaque_up);
43+
return *this;
44+
}
45+
46+
SBWatchpointOptions::~SBWatchpointOptions() = default;
47+
48+
void SBWatchpointOptions::SetWatchpointTypeRead(bool read) {
49+
m_opaque_up->m_read = read;
50+
}
51+
bool SBWatchpointOptions::GetWatchpointTypeRead() const {
52+
return m_opaque_up->m_read;
53+
}
54+
55+
void SBWatchpointOptions::SetWatchpointTypeWrite(
56+
WatchpointWriteType write_type) {
57+
if (write_type == eWatchpointWriteTypeOnModify) {
58+
m_opaque_up->m_write = false;
59+
m_opaque_up->m_modify = true;
60+
} else if (write_type == eWatchpointWriteTypeAlways) {
61+
m_opaque_up->m_write = true;
62+
m_opaque_up->m_modify = false;
63+
} else
64+
m_opaque_up->m_write = m_opaque_up->m_modify = false;
65+
}
66+
67+
WatchpointWriteType SBWatchpointOptions::GetWatchpointTypeWrite() const {
68+
if (m_opaque_up->m_modify)
69+
return eWatchpointWriteTypeOnModify;
70+
if (m_opaque_up->m_write)
71+
return eWatchpointWriteTypeAlways;
72+
return eWatchpointWriteTypeDisabled;
73+
}

0 commit comments

Comments
 (0)