toolbox 0.1.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/bake/ruby/gdb.rb +135 -0
- data/bake/toolbox/gdb.rb +137 -0
- data/bake/toolbox/lldb.rb +137 -0
- data/context/fiber-debugging.md +171 -0
- data/context/getting-started.md +200 -0
- data/context/heap-debugging.md +351 -0
- data/context/index.yaml +28 -0
- data/context/object-inspection.md +208 -0
- data/context/stack-inspection.md +188 -0
- data/data/toolbox/command.py +479 -0
- data/data/toolbox/constants.py +200 -0
- data/data/toolbox/context.py +371 -0
- data/data/toolbox/debugger/__init__.py +101 -0
- data/data/toolbox/debugger/gdb_backend.py +664 -0
- data/data/toolbox/debugger/lldb_backend.py +986 -0
- data/data/toolbox/fiber.py +877 -0
- data/data/toolbox/format.py +205 -0
- data/data/toolbox/heap.py +679 -0
- data/data/toolbox/init.py +89 -0
- data/data/toolbox/print.py +79 -0
- data/data/toolbox/rarray.py +116 -0
- data/data/toolbox/rbasic.py +99 -0
- data/data/toolbox/rbignum.py +48 -0
- data/data/toolbox/rclass.py +136 -0
- data/data/toolbox/readme.md +214 -0
- data/data/toolbox/rexception.py +150 -0
- data/data/toolbox/rfloat.py +88 -0
- data/data/toolbox/rhash.py +151 -0
- data/data/toolbox/rstring.py +230 -0
- data/data/toolbox/rstruct.py +149 -0
- data/data/toolbox/rsymbol.py +278 -0
- data/data/toolbox/rvalue.py +183 -0
- data/data/toolbox/stack.py +620 -0
- data/lib/toolbox/gdb.rb +21 -0
- data/lib/toolbox/lldb.rb +21 -0
- data/lib/toolbox/version.rb +7 -1
- data/lib/toolbox.rb +9 -24
- data/license.md +21 -0
- data/readme.md +64 -0
- data/releases.md +9 -0
- data.tar.gz.sig +0 -0
- metadata +95 -165
- metadata.gz.sig +0 -0
- data/Rakefile +0 -61
- data/lib/dirs.rb +0 -9
- data/lib/toolbox/config.rb +0 -211
- data/lib/toolbox/default_controller.rb +0 -393
- data/lib/toolbox/helpers.rb +0 -11
- data/lib/toolbox/rendering.rb +0 -413
- data/lib/toolbox/searching.rb +0 -85
- data/lib/toolbox/session_params.rb +0 -63
- data/lib/toolbox/sorting.rb +0 -74
- data/locale/de/LC_MESSAGES/toolbox.mo +0 -0
- data/public/images/add.png +0 -0
- data/public/images/arrow_down.gif +0 -0
- data/public/images/arrow_up.gif +0 -0
- data/public/images/close.png +0 -0
- data/public/images/edit.gif +0 -0
- data/public/images/email.png +0 -0
- data/public/images/page.png +0 -0
- data/public/images/page_acrobat.png +0 -0
- data/public/images/page_add.png +0 -0
- data/public/images/page_copy.png +0 -0
- data/public/images/page_delete.png +0 -0
- data/public/images/page_edit.png +0 -0
- data/public/images/page_excel.png +0 -0
- data/public/images/page_list.png +0 -0
- data/public/images/page_save.png +0 -0
- data/public/images/page_word.png +0 -0
- data/public/images/remove.png +0 -0
- data/public/images/show.gif +0 -0
- data/public/images/spinner.gif +0 -0
- data/public/javascripts/popup.js +0 -498
- data/public/javascripts/toolbox.js +0 -18
- data/public/stylesheets/context_menu.css +0 -168
- data/public/stylesheets/popup.css +0 -30
- data/public/stylesheets/toolbox.css +0 -107
- data/view/toolbox/_collection.html.erb +0 -24
- data/view/toolbox/_collection_header.html.erb +0 -7
- data/view/toolbox/_context_menu.html.erb +0 -17
- data/view/toolbox/_dialogs.html.erb +0 -6
- data/view/toolbox/_form.html.erb +0 -30
- data/view/toolbox/_form_collection_row.html.erb +0 -18
- data/view/toolbox/_form_fieldset.html.erb +0 -30
- data/view/toolbox/_form_fieldset_row.html.erb +0 -19
- data/view/toolbox/_list.html.erb +0 -25
- data/view/toolbox/_list_row.html.erb +0 -10
- data/view/toolbox/_menu.html.erb +0 -7
- data/view/toolbox/_search_field.html.erb +0 -8
- data/view/toolbox/_show.html.erb +0 -12
- data/view/toolbox/_show_collection_row.html.erb +0 -6
- data/view/toolbox/_show_fieldset.html.erb +0 -21
- data/view/toolbox/edit.html.erb +0 -5
- data/view/toolbox/index.html.erb +0 -3
- data/view/toolbox/new.html.erb +0 -9
- data/view/toolbox/show.html.erb +0 -39
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"""Ruby execution context utilities and commands."""
|
|
2
|
+
|
|
3
|
+
import debugger
|
|
4
|
+
import command
|
|
5
|
+
import format
|
|
6
|
+
import rvalue
|
|
7
|
+
import rexception
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RubyContext:
|
|
11
|
+
"""Wrapper for Ruby execution context (rb_execution_context_t).
|
|
12
|
+
|
|
13
|
+
Provides a high-level interface for working with Ruby execution contexts,
|
|
14
|
+
including inspection, convenience variable setup, and information display.
|
|
15
|
+
|
|
16
|
+
Example:
|
|
17
|
+
ctx = RubyContext.current()
|
|
18
|
+
if ctx:
|
|
19
|
+
ctx.print_info(terminal)
|
|
20
|
+
ctx.setup_convenience_variables()
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, ec):
|
|
24
|
+
"""Create a RubyContext wrapper.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
ec: Execution context pointer (rb_execution_context_t *)
|
|
28
|
+
"""
|
|
29
|
+
self.ec = ec
|
|
30
|
+
self._cfp = None
|
|
31
|
+
self._errinfo = None
|
|
32
|
+
self._vm_stack = None
|
|
33
|
+
self._vm_stack_size = None
|
|
34
|
+
|
|
35
|
+
@classmethod
|
|
36
|
+
def current(cls):
|
|
37
|
+
"""Get the current execution context from the running thread.
|
|
38
|
+
|
|
39
|
+
Tries multiple approaches in order of preference:
|
|
40
|
+
1. ruby_current_ec - TLS variable (works in GDB, some LLDB)
|
|
41
|
+
2. rb_current_ec_noinline() - function call (works in most cases)
|
|
42
|
+
3. rb_current_ec() - macOS-specific function
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
RubyContext instance, or None if not available
|
|
46
|
+
"""
|
|
47
|
+
# Try ruby_current_ec variable first
|
|
48
|
+
try:
|
|
49
|
+
ec = debugger.parse_and_eval('ruby_current_ec')
|
|
50
|
+
if ec is not None and int(ec) != 0:
|
|
51
|
+
return cls(ec)
|
|
52
|
+
except debugger.Error:
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
# Fallback to rb_current_ec_noinline() function
|
|
56
|
+
try:
|
|
57
|
+
ec = debugger.parse_and_eval('rb_current_ec_noinline()')
|
|
58
|
+
if ec is not None and int(ec) != 0:
|
|
59
|
+
return cls(ec)
|
|
60
|
+
except debugger.Error:
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
# Last resort: rb_current_ec() (macOS-specific)
|
|
64
|
+
try:
|
|
65
|
+
ec = debugger.parse_and_eval('rb_current_ec()')
|
|
66
|
+
if ec is not None and int(ec) != 0:
|
|
67
|
+
return cls(ec)
|
|
68
|
+
except debugger.Error:
|
|
69
|
+
pass
|
|
70
|
+
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def cfp(self):
|
|
75
|
+
"""Get control frame pointer (lazy load)."""
|
|
76
|
+
if self._cfp is None:
|
|
77
|
+
try:
|
|
78
|
+
self._cfp = self.ec['cfp']
|
|
79
|
+
except Exception:
|
|
80
|
+
pass
|
|
81
|
+
return self._cfp
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def errinfo(self):
|
|
85
|
+
"""Get exception VALUE (lazy load)."""
|
|
86
|
+
if self._errinfo is None:
|
|
87
|
+
try:
|
|
88
|
+
self._errinfo = self.ec['errinfo']
|
|
89
|
+
except Exception:
|
|
90
|
+
pass
|
|
91
|
+
return self._errinfo
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def has_exception(self):
|
|
95
|
+
"""Check if there's a real exception (not nil/special value)."""
|
|
96
|
+
if self.errinfo is None:
|
|
97
|
+
return False
|
|
98
|
+
return rexception.is_exception(self.errinfo)
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def vm_stack(self):
|
|
102
|
+
"""Get VM stack pointer (lazy load)."""
|
|
103
|
+
if self._vm_stack is None:
|
|
104
|
+
try:
|
|
105
|
+
self._vm_stack = self.ec['vm_stack']
|
|
106
|
+
except Exception:
|
|
107
|
+
pass
|
|
108
|
+
return self._vm_stack
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def vm_stack_size(self):
|
|
112
|
+
"""Get VM stack size (lazy load)."""
|
|
113
|
+
if self._vm_stack_size is None:
|
|
114
|
+
try:
|
|
115
|
+
self._vm_stack_size = int(self.ec['vm_stack_size'])
|
|
116
|
+
except Exception:
|
|
117
|
+
pass
|
|
118
|
+
return self._vm_stack_size
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def storage(self):
|
|
122
|
+
"""Get fiber storage VALUE."""
|
|
123
|
+
try:
|
|
124
|
+
return self.ec['storage']
|
|
125
|
+
except Exception:
|
|
126
|
+
return None
|
|
127
|
+
|
|
128
|
+
def setup_convenience_variables(self):
|
|
129
|
+
"""Set up convenience variables for this execution context.
|
|
130
|
+
|
|
131
|
+
Sets:
|
|
132
|
+
$ec - Execution context pointer
|
|
133
|
+
$cfp - Control frame pointer
|
|
134
|
+
$errinfo - Current exception (if any)
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
dict with keys: 'ec', 'cfp', 'errinfo' (values are the set variables)
|
|
138
|
+
"""
|
|
139
|
+
result = {}
|
|
140
|
+
|
|
141
|
+
# Set $ec
|
|
142
|
+
debugger.set_convenience_variable('ec', self.ec)
|
|
143
|
+
result['ec'] = self.ec
|
|
144
|
+
|
|
145
|
+
# Set $cfp (control frame pointer)
|
|
146
|
+
if self.cfp is not None:
|
|
147
|
+
debugger.set_convenience_variable('cfp', self.cfp)
|
|
148
|
+
result['cfp'] = self.cfp
|
|
149
|
+
else:
|
|
150
|
+
result['cfp'] = None
|
|
151
|
+
|
|
152
|
+
# Set $errinfo if there's an exception
|
|
153
|
+
if self.has_exception:
|
|
154
|
+
debugger.set_convenience_variable('errinfo', self.errinfo)
|
|
155
|
+
result['errinfo'] = self.errinfo
|
|
156
|
+
else:
|
|
157
|
+
result['errinfo'] = None
|
|
158
|
+
|
|
159
|
+
return result
|
|
160
|
+
|
|
161
|
+
def print_info(self, terminal):
|
|
162
|
+
"""Print detailed information about this execution context.
|
|
163
|
+
|
|
164
|
+
Args:
|
|
165
|
+
terminal: Terminal formatter for output
|
|
166
|
+
"""
|
|
167
|
+
# Cache property lookups
|
|
168
|
+
vm_stack = self.vm_stack
|
|
169
|
+
vm_stack_size = self.vm_stack_size
|
|
170
|
+
cfp = self.cfp
|
|
171
|
+
storage = self.storage
|
|
172
|
+
errinfo = self.errinfo
|
|
173
|
+
has_exception = self.has_exception
|
|
174
|
+
|
|
175
|
+
terminal.print("Execution Context:")
|
|
176
|
+
terminal.print(f" $ec = ", end='')
|
|
177
|
+
terminal.print_type_tag('rb_execution_context_t', int(self.ec), None)
|
|
178
|
+
terminal.print()
|
|
179
|
+
|
|
180
|
+
# VM Stack info
|
|
181
|
+
if vm_stack is not None and vm_stack_size is not None:
|
|
182
|
+
terminal.print(f" VM Stack: ", end='')
|
|
183
|
+
terminal.print_type_tag('VALUE', int(vm_stack))
|
|
184
|
+
terminal.print()
|
|
185
|
+
else:
|
|
186
|
+
terminal.print(f" VM Stack: <unavailable>")
|
|
187
|
+
|
|
188
|
+
# Control Frame info
|
|
189
|
+
if cfp is not None:
|
|
190
|
+
terminal.print(f" $cfp = ", end='')
|
|
191
|
+
terminal.print_type_tag('rb_control_frame_t', int(cfp), None)
|
|
192
|
+
terminal.print()
|
|
193
|
+
else:
|
|
194
|
+
terminal.print(f" $cfp = <unavailable>")
|
|
195
|
+
|
|
196
|
+
# Storage info
|
|
197
|
+
if storage is not None and not rvalue.is_nil(storage):
|
|
198
|
+
terminal.print(f" Storage: ", end='')
|
|
199
|
+
terminal.print_type_tag('VALUE', int(storage), None)
|
|
200
|
+
terminal.print()
|
|
201
|
+
|
|
202
|
+
# Exception info
|
|
203
|
+
if has_exception:
|
|
204
|
+
terminal.print(" $errinfo = ", end='')
|
|
205
|
+
terminal.print_type_tag('VALUE', int(errinfo), None)
|
|
206
|
+
terminal.print()
|
|
207
|
+
terminal.print(" Exception present!")
|
|
208
|
+
else:
|
|
209
|
+
errinfo_int = int(errinfo) if errinfo else 0
|
|
210
|
+
if errinfo_int == 4: # Qnil
|
|
211
|
+
terminal.print(" Exception: None")
|
|
212
|
+
elif errinfo_int == 0: # Qfalse
|
|
213
|
+
terminal.print(" Exception: None (false)")
|
|
214
|
+
else:
|
|
215
|
+
terminal.print(" Exception: None")
|
|
216
|
+
|
|
217
|
+
# Tag info (for ensure blocks)
|
|
218
|
+
try:
|
|
219
|
+
tag = self.ec['tag']
|
|
220
|
+
tag_int = int(tag)
|
|
221
|
+
if tag_int != 0:
|
|
222
|
+
terminal.print(" Tag: ", end='')
|
|
223
|
+
terminal.print_type_tag('rb_vm_tag', tag_int, None)
|
|
224
|
+
terminal.print()
|
|
225
|
+
try:
|
|
226
|
+
retval = tag['retval']
|
|
227
|
+
retval_int = int(retval)
|
|
228
|
+
is_retval_special = (retval_int & 0x03) != 0 or retval_int == 0
|
|
229
|
+
if not is_retval_special:
|
|
230
|
+
terminal.print(" $retval available (in ensure block)")
|
|
231
|
+
except Exception:
|
|
232
|
+
pass
|
|
233
|
+
except Exception:
|
|
234
|
+
pass
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class RubyContextHandler:
|
|
238
|
+
"""Show current execution context and set convenience variables."""
|
|
239
|
+
|
|
240
|
+
USAGE = command.Usage(
|
|
241
|
+
summary="Show current execution context and set convenience variables",
|
|
242
|
+
parameters=[],
|
|
243
|
+
options={},
|
|
244
|
+
flags=[],
|
|
245
|
+
examples=[
|
|
246
|
+
("rb-context", "Display execution context info"),
|
|
247
|
+
("rb-context; rb-print $errinfo", "Show context then print exception")
|
|
248
|
+
]
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
def invoke(self, arguments, terminal):
|
|
252
|
+
"""Execute the rb-context command."""
|
|
253
|
+
try:
|
|
254
|
+
# Get current execution context
|
|
255
|
+
ctx = RubyContext.current()
|
|
256
|
+
|
|
257
|
+
if ctx is None:
|
|
258
|
+
print("Error: Could not get current execution context")
|
|
259
|
+
print()
|
|
260
|
+
print("Possible reasons:")
|
|
261
|
+
print(" • Ruby symbols not loaded (compile with debug symbols)")
|
|
262
|
+
print(" • Process not stopped at a Ruby frame")
|
|
263
|
+
print(" • Ruby not fully initialized yet")
|
|
264
|
+
print()
|
|
265
|
+
print("Try:")
|
|
266
|
+
print(" • Break at a Ruby function: break rb_vm_exec")
|
|
267
|
+
print(" • Use rb-fiber-scan-switch to switch to a fiber")
|
|
268
|
+
print(" • Ensure Ruby debug symbols are available")
|
|
269
|
+
return
|
|
270
|
+
|
|
271
|
+
# Print context information
|
|
272
|
+
ctx.print_info(terminal)
|
|
273
|
+
|
|
274
|
+
# Set convenience variables
|
|
275
|
+
vars = ctx.setup_convenience_variables()
|
|
276
|
+
|
|
277
|
+
print()
|
|
278
|
+
print("Convenience variables set:")
|
|
279
|
+
print(f" $ec - Execution context")
|
|
280
|
+
if vars.get('cfp'):
|
|
281
|
+
print(f" $cfp - Control frame pointer")
|
|
282
|
+
if vars.get('errinfo'):
|
|
283
|
+
print(f" $errinfo - Exception object")
|
|
284
|
+
|
|
285
|
+
print()
|
|
286
|
+
print("Now you can use:")
|
|
287
|
+
print(" rb-print $errinfo")
|
|
288
|
+
print(" rb-print $ec->cfp->sp[-1]")
|
|
289
|
+
print(" rb-stack-trace")
|
|
290
|
+
|
|
291
|
+
except Exception as e:
|
|
292
|
+
print(f"Error: {e}")
|
|
293
|
+
import traceback
|
|
294
|
+
traceback.print_exc()
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
class RubyContextStorageHandler:
|
|
298
|
+
"""Print the fiber storage from the current execution context."""
|
|
299
|
+
|
|
300
|
+
USAGE = command.Usage(
|
|
301
|
+
summary="Print fiber storage from current execution context",
|
|
302
|
+
parameters=[],
|
|
303
|
+
options={'depth': (int, 1, 'Recursion depth for nested objects')},
|
|
304
|
+
flags=[('debug', 'Show debug information')],
|
|
305
|
+
examples=[
|
|
306
|
+
("rb-context-storage", "Print storage with default depth"),
|
|
307
|
+
("rb-context-storage --depth 3", "Print storage with depth 3")
|
|
308
|
+
]
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
def invoke(self, arguments, terminal):
|
|
312
|
+
"""Execute the rb-context-storage command."""
|
|
313
|
+
try:
|
|
314
|
+
# Get current execution context
|
|
315
|
+
ctx = RubyContext.current()
|
|
316
|
+
|
|
317
|
+
if ctx is None:
|
|
318
|
+
print("Error: Could not get current execution context")
|
|
319
|
+
print("\nTry:")
|
|
320
|
+
print(" • Run rb-context first to set up execution context")
|
|
321
|
+
print(" • Break at a Ruby function")
|
|
322
|
+
print(" • Use rb-fiber-scan-switch to switch to a fiber")
|
|
323
|
+
return
|
|
324
|
+
|
|
325
|
+
# Get storage
|
|
326
|
+
storage_val = ctx.storage
|
|
327
|
+
|
|
328
|
+
if storage_val is None:
|
|
329
|
+
print("Error: Could not access fiber storage")
|
|
330
|
+
return
|
|
331
|
+
|
|
332
|
+
# Check if it's nil
|
|
333
|
+
if rvalue.is_nil(storage_val):
|
|
334
|
+
print("Fiber storage: nil")
|
|
335
|
+
return
|
|
336
|
+
|
|
337
|
+
# Parse arguments (--depth, --debug, etc.)
|
|
338
|
+
arguments = command.parse_arguments(arg if arg else "")
|
|
339
|
+
|
|
340
|
+
# Get depth flag
|
|
341
|
+
depth = 1 # Default depth
|
|
342
|
+
depth_str = arguments.get_option('depth')
|
|
343
|
+
if depth_str:
|
|
344
|
+
try:
|
|
345
|
+
depth = int(depth_str)
|
|
346
|
+
except ValueError:
|
|
347
|
+
print(f"Error: invalid depth '{depth_str}'")
|
|
348
|
+
return
|
|
349
|
+
|
|
350
|
+
# Get debug flag
|
|
351
|
+
debug = arguments.has_flag('debug')
|
|
352
|
+
|
|
353
|
+
# Use print module to print the storage
|
|
354
|
+
import print as print_module
|
|
355
|
+
printer = print_module.RubyObjectPrinter()
|
|
356
|
+
|
|
357
|
+
# Build arguments for the printer
|
|
358
|
+
flags_set = {'debug'} if debug else set()
|
|
359
|
+
args_for_printer = command.Arguments([storage_val], flags_set, {'depth': depth})
|
|
360
|
+
|
|
361
|
+
printer.invoke(args_for_printer, terminal)
|
|
362
|
+
|
|
363
|
+
except Exception as e:
|
|
364
|
+
print(f"Error: {e}")
|
|
365
|
+
import traceback
|
|
366
|
+
traceback.print_exc()
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
# Register commands
|
|
370
|
+
debugger.register("rb-context", RubyContextHandler, usage=RubyContextHandler.USAGE)
|
|
371
|
+
debugger.register("rb-context-storage", RubyContextStorageHandler, usage=RubyContextStorageHandler.USAGE)
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Unified debugger abstraction layer for GDB and LLDB.
|
|
3
|
+
|
|
4
|
+
This module provides a common interface for debugger operations,
|
|
5
|
+
automatically loading the appropriate backend (GDB or LLDB) at runtime.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
import os
|
|
10
|
+
|
|
11
|
+
# Detect which debugger we're running under
|
|
12
|
+
_backend = None
|
|
13
|
+
DEBUGGER_NAME = None
|
|
14
|
+
|
|
15
|
+
# Add parent directory to path so we can import debugger.gdb / debugger.lldb
|
|
16
|
+
_toolbox_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
17
|
+
if _toolbox_dir not in sys.path:
|
|
18
|
+
sys.path.insert(0, _toolbox_dir)
|
|
19
|
+
|
|
20
|
+
# Try importing the real GDB or LLDB modules first
|
|
21
|
+
# We need to verify they're the actual debugger modules, not namespace packages
|
|
22
|
+
_gdb_available = False
|
|
23
|
+
_lldb_available = False
|
|
24
|
+
|
|
25
|
+
try:
|
|
26
|
+
import gdb as _gdb_module
|
|
27
|
+
# Verify it's the real GDB module by checking for a key attribute
|
|
28
|
+
if hasattr(_gdb_module, 'COMMAND_DATA'):
|
|
29
|
+
_gdb_available = True
|
|
30
|
+
except ImportError:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
import lldb as _lldb_module
|
|
35
|
+
# Verify it's the real LLDB module by checking for a key class
|
|
36
|
+
if hasattr(_lldb_module, 'SBDebugger'):
|
|
37
|
+
_lldb_available = True
|
|
38
|
+
except ImportError:
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
# Now load the appropriate backend based on which module is available
|
|
42
|
+
if _gdb_available:
|
|
43
|
+
from debugger import gdb_backend as _backend
|
|
44
|
+
DEBUGGER_NAME = 'gdb'
|
|
45
|
+
elif _lldb_available:
|
|
46
|
+
from debugger import lldb_backend as _backend
|
|
47
|
+
DEBUGGER_NAME = 'lldb'
|
|
48
|
+
else:
|
|
49
|
+
raise RuntimeError("Must be run under GDB or LLDB - neither module found")
|
|
50
|
+
|
|
51
|
+
if _backend is None:
|
|
52
|
+
raise RuntimeError("Failed to load debugger backend")
|
|
53
|
+
|
|
54
|
+
# Export the backend's interface
|
|
55
|
+
Value = _backend.Value
|
|
56
|
+
Type = _backend.Type
|
|
57
|
+
Command = _backend.Command
|
|
58
|
+
Error = _backend.Error
|
|
59
|
+
MemoryError = _backend.MemoryError
|
|
60
|
+
|
|
61
|
+
parse_and_eval = _backend.parse_and_eval
|
|
62
|
+
lookup_type = _backend.lookup_type
|
|
63
|
+
set_convenience_variable = _backend.set_convenience_variable
|
|
64
|
+
execute = _backend.execute
|
|
65
|
+
lookup_symbol = _backend.lookup_symbol
|
|
66
|
+
invalidate_cached_frames = _backend.invalidate_cached_frames
|
|
67
|
+
get_enum_value = _backend.get_enum_value
|
|
68
|
+
read_memory = _backend.read_memory
|
|
69
|
+
read_cstring = _backend.read_cstring
|
|
70
|
+
create_value = _backend.create_value
|
|
71
|
+
create_value_from_int = _backend.create_value_from_int
|
|
72
|
+
create_value_from_address = _backend.create_value_from_address
|
|
73
|
+
register = _backend.register
|
|
74
|
+
|
|
75
|
+
# Constants
|
|
76
|
+
COMMAND_DATA = _backend.COMMAND_DATA
|
|
77
|
+
COMMAND_USER = _backend.COMMAND_USER
|
|
78
|
+
|
|
79
|
+
__all__ = [
|
|
80
|
+
'DEBUGGER_NAME',
|
|
81
|
+
'Value',
|
|
82
|
+
'Type',
|
|
83
|
+
'Command',
|
|
84
|
+
'Error',
|
|
85
|
+
'MemoryError',
|
|
86
|
+
'parse_and_eval',
|
|
87
|
+
'lookup_type',
|
|
88
|
+
'set_convenience_variable',
|
|
89
|
+
'execute',
|
|
90
|
+
'lookup_symbol',
|
|
91
|
+
'invalidate_cached_frames',
|
|
92
|
+
'get_enum_value',
|
|
93
|
+
'read_memory',
|
|
94
|
+
'read_cstring',
|
|
95
|
+
'create_value',
|
|
96
|
+
'create_value_from_int',
|
|
97
|
+
'create_value_from_address',
|
|
98
|
+
'register',
|
|
99
|
+
'COMMAND_DATA',
|
|
100
|
+
'COMMAND_USER',
|
|
101
|
+
]
|