24
24
import gdb
25
25
26
26
from gdbmongo import stdlib_printers
27
+ from gdbmongo .gdbutil import gdb_lookup_value
27
28
from gdbmongo .printer_protocol import LazyString , SupportsDisplayHint , SupportsToString
28
29
29
30
@@ -93,9 +94,74 @@ class c_size_t(ctypes.c_size_t):
93
94
94
95
95
96
@dataclasses .dataclass
96
- class MongoStringData (ctypes .Structure ):
97
+ class MongoStringDataLayoutStdStringView (ctypes .Structure ):
97
98
"""Structure with a memory layout compatible with that of mongo::StringData.
98
99
100
+ It corresponds to the memory layout after mongo::StringData became a thin wrapper over
101
+ std::string_view as part of SERVER-82604 in MongoDB 7.3. It is equivalent to the following
102
+ C struct:
103
+
104
+ .. code-block:: c
105
+
106
+ struct {
107
+ size_t size;
108
+ char* data;
109
+ };
110
+ """
111
+
112
+ size : c_size_t
113
+ data : c_char_p
114
+
115
+
116
+ setattr (MongoStringDataLayoutStdStringView , "_fields_" ,
117
+ [(field .name , field .type )
118
+ for field in dataclasses .fields (MongoStringDataLayoutStdStringView )])
119
+
120
+
121
+ @dataclasses .dataclass
122
+ class MongoStringDataLayoutPre73 (ctypes .Structure ):
123
+ """Structure with a memory layout compatible with that of mongo::StringData.
124
+
125
+ It corresponds to the memory layout prior to mongo::StringData being made a thin wrapper over
126
+ std::string_view as part of SERVER-82604 in MongoDB 7.3. It is equivalent to the following
127
+ C struct:
128
+
129
+ .. code-block:: c
130
+
131
+ struct {
132
+ char* data;
133
+ size_t size;
134
+ };
135
+ """
136
+
137
+ data : c_char_p
138
+ size : c_size_t
139
+
140
+
141
+ setattr (MongoStringDataLayoutPre73 , "_fields_" ,
142
+ [(field .name , field .type ) for field in dataclasses .fields (MongoStringDataLayoutPre73 )])
143
+
144
+
145
+ class MongoStringData (ctypes .Union ):
146
+ """Object with a memory layout compatible with that of mongo::StringData.
147
+
148
+ It is implemented as a ctypes.Union to accommodate the memory layout of mongo::StringData
149
+ changing between MongoDB Server versions. It is equivalent to the following C union:
150
+
151
+ .. code-block:: c
152
+
153
+ union {
154
+ struct {
155
+ size_t size;
156
+ char* data;
157
+ } layout_string_view;
158
+
159
+ struct {
160
+ char* data;
161
+ size_t size;
162
+ } layout_pre73;
163
+ };
164
+
99
165
This class is useful for constructing gdb.Value objects of type mongo::StringData out of
100
166
selected portions of a buffer read with gdb.Inferior.read_memory(). These synthetic gdb.Values
101
167
can then be formatted by StringDataPrinter like normal.
@@ -107,14 +173,24 @@ class MongoStringData(ctypes.Structure):
107
173
yield (f"{i}", string_data.to_value())
108
174
"""
109
175
110
- data : c_char_p
111
- size : c_size_t
176
+ layout_string_view : MongoStringDataLayoutStdStringView
177
+ layout_pre73 : MongoStringDataLayoutPre73
178
+
179
+ # dataclasses.dataclass doesn't appear to be compatible with ctypes.Union. We enumerate
180
+ # `MongoStringData._fields_` explicitly instead of relying on the type annotations.
181
+ _fields_ = [("layout_string_view" , MongoStringDataLayoutStdStringView ),
182
+ ("layout_pre73" , MongoStringDataLayoutPre73 )]
112
183
113
184
def __init__ (self , * , data : int , size : int ) -> None :
114
185
if size < 0 :
115
186
raise ValueError ("size argument must be a non-negative integer" )
116
187
117
- super ().__init__ (data = c_char_p (data ), size = c_size_t (size ))
188
+ if StringDataPrinter .is_wrapping_std_string_view ():
189
+ super ().__init__ (layout_string_view = MongoStringDataLayoutStdStringView (
190
+ data = c_char_p (data ), size = c_size_t (size )))
191
+ else :
192
+ super ().__init__ (
193
+ layout_pre73 = MongoStringDataLayoutPre73 (data = c_char_p (data ), size = c_size_t (size )))
118
194
119
195
@classmethod
120
196
def from_cstring (cls , val : gdb .Value , / , * , maxsize : int ) -> "MongoStringData" :
@@ -132,33 +208,49 @@ def from_pascalstring(cls, val: gdb.Value, /, *, view: memoryview) -> "MongoStri
132
208
"""Read a length-prefixed string starting from the beginning of the given buffer."""
133
209
fmt = "<i"
134
210
(size , ) = struct .unpack_from (fmt , view )
211
+
135
212
return cls (data = int (val + struct .calcsize (fmt )), size = size )
136
213
214
+ @property
215
+ def data (self ) -> c_char_p :
216
+ """Return the pointer to the first character in the string."""
217
+ return (self .layout_string_view .data
218
+ if StringDataPrinter .is_wrapping_std_string_view () else self .layout_pre73 .data )
219
+
220
+ @property
221
+ def size (self ) -> c_size_t :
222
+ """Return the number of characters in the string."""
223
+ return (self .layout_string_view .size
224
+ if StringDataPrinter .is_wrapping_std_string_view () else self .layout_pre73 .size )
225
+
137
226
def to_value (self ) -> gdb .Value :
138
227
"""Convert the structure to a gdb.Value of type mongo::StringData."""
139
228
typ = gdb .lookup_type ("mongo::StringData" )
140
229
return gdb .Value (memoryview (self ), typ )
141
230
142
231
143
- setattr (MongoStringData , "_fields_" ,
144
- [(field .name , field .type ) for field in dataclasses .fields (MongoStringData )])
145
-
146
-
147
232
class StringDataPrinter (SupportsDisplayHint , ValueAsPythonStringMixin ):
148
233
# pylint: disable=missing-function-docstring
149
234
"""Pretty-printer for mongo::StringData."""
150
235
151
236
def __init__ (self , val : gdb .Value , / ) -> None :
152
237
self .val = val
153
- self .size = val ["_size" ]
154
- self .data = val ["_data" ]
155
238
156
239
@staticmethod
157
240
def display_hint () -> typing .Literal ["string" ]:
158
241
return "string"
159
242
160
- def to_string (self ) -> LazyString :
161
- return self .data .lazy_string (length = int (self .size ))
243
+ def to_string (self ) -> typing .Union [gdb .Value , LazyString ]:
244
+ if StringDataPrinter .is_wrapping_std_string_view ():
245
+ return self .val ["_sv" ]
246
+
247
+ return self .val ["_data" ].lazy_string (length = int (self .val ["_size" ]))
248
+
249
+ @staticmethod
250
+ def is_wrapping_std_string_view () -> bool :
251
+ # The StringData class was changed to be a thin wrapper over std::string_view as part of
252
+ # SERVER-82604 in MongoDB 7.3.
253
+ return gdb_lookup_value ("mongo::StringData::npos" ) is not None
162
254
163
255
164
256
def add_printers (pretty_printer : gdb .printing .RegexpCollectionPrettyPrinter , / ) -> None :
0 commit comments