ruby-gdb 0.1.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
- data/bake/ruby/gdb.rb +135 -0
- data/context/fiber-debugging.md +372 -0
- data/context/getting-started.md +167 -0
- data/context/heap-debugging.md +426 -0
- data/context/index.yaml +28 -0
- data/context/object-inspection.md +272 -0
- data/context/stack-inspection.md +357 -0
- data/data/ruby/gdb/command.py +254 -0
- data/data/ruby/gdb/constants.py +59 -0
- data/data/ruby/gdb/fiber.py +825 -0
- data/data/ruby/gdb/format.py +201 -0
- data/data/ruby/gdb/heap.py +563 -0
- data/data/ruby/gdb/init.py +25 -0
- data/data/ruby/gdb/object.py +85 -0
- data/data/ruby/gdb/rarray.py +124 -0
- data/data/ruby/gdb/rbasic.py +103 -0
- data/data/ruby/gdb/rbignum.py +52 -0
- data/data/ruby/gdb/rclass.py +133 -0
- data/data/ruby/gdb/rexception.py +150 -0
- data/data/ruby/gdb/rfloat.py +95 -0
- data/data/ruby/gdb/rhash.py +157 -0
- data/data/ruby/gdb/rstring.py +217 -0
- data/data/ruby/gdb/rstruct.py +157 -0
- data/data/ruby/gdb/rsymbol.py +291 -0
- data/data/ruby/gdb/stack.py +609 -0
- data/data/ruby/gdb/value.py +181 -0
- data/lib/ruby/gdb/version.rb +13 -0
- data/lib/ruby/gdb.rb +23 -0
- data/license.md +21 -0
- data/readme.md +42 -0
- metadata +69 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ANSI color codes for GDB output formatting.
|
|
3
|
+
|
|
4
|
+
This module provides utilities for colorizing GDB output to make metadata
|
|
5
|
+
less prominent and values more readable.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
class Style:
|
|
11
|
+
"""Sentinel object representing a style."""
|
|
12
|
+
def __init__(self, name):
|
|
13
|
+
self.name = name
|
|
14
|
+
|
|
15
|
+
def __repr__(self):
|
|
16
|
+
return f"Style({self.name})"
|
|
17
|
+
|
|
18
|
+
# Style sentinels
|
|
19
|
+
reset = Style('reset')
|
|
20
|
+
metadata = Style('metadata')
|
|
21
|
+
address = Style('address')
|
|
22
|
+
type = Style('type')
|
|
23
|
+
value = Style('value')
|
|
24
|
+
string = Style('string')
|
|
25
|
+
number = Style('number')
|
|
26
|
+
symbol = Style('symbol')
|
|
27
|
+
method = Style('method') # Alias for symbol (method names)
|
|
28
|
+
error = Style('error')
|
|
29
|
+
bold = Style('bold')
|
|
30
|
+
dim = Style('dim')
|
|
31
|
+
|
|
32
|
+
class Text:
|
|
33
|
+
"""Plain text output without any formatting."""
|
|
34
|
+
|
|
35
|
+
def print(self, *args):
|
|
36
|
+
"""Print arguments, skipping style sentinels."""
|
|
37
|
+
result = []
|
|
38
|
+
for arg in args:
|
|
39
|
+
# Skip Style sentinels
|
|
40
|
+
if not isinstance(arg, Style):
|
|
41
|
+
# If arg has a print_to method, use it
|
|
42
|
+
if hasattr(arg, 'print_to'):
|
|
43
|
+
result.append(arg.print_to(self))
|
|
44
|
+
else:
|
|
45
|
+
result.append(str(arg))
|
|
46
|
+
return "".join(result)
|
|
47
|
+
|
|
48
|
+
def print_type_tag(self, type_name, address_val=None, details=None):
|
|
49
|
+
"""
|
|
50
|
+
Format a type tag like <T_ARRAY@0xABCD embedded length=3>.
|
|
51
|
+
|
|
52
|
+
Arguments:
|
|
53
|
+
type_name: Type name (e.g., "T_ARRAY", "void *")
|
|
54
|
+
address_val: Optional hex address (as integer or hex string without 0x)
|
|
55
|
+
details: Optional details string (e.g., "embedded length=3")
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
Formatted string with appropriate styling
|
|
59
|
+
"""
|
|
60
|
+
if isinstance(address_val, int):
|
|
61
|
+
address_val = f"{address_val:x}"
|
|
62
|
+
|
|
63
|
+
parts = [metadata, '<', type, type_name]
|
|
64
|
+
|
|
65
|
+
if address_val:
|
|
66
|
+
parts.extend([metadata, f'@0x{address_val}'])
|
|
67
|
+
|
|
68
|
+
if details:
|
|
69
|
+
parts.extend([f' {details}'])
|
|
70
|
+
|
|
71
|
+
parts.extend([metadata, '>', reset])
|
|
72
|
+
|
|
73
|
+
return self.print(*parts)
|
|
74
|
+
|
|
75
|
+
def print_value_with_tag(self, type_tag, val=None, value_style=value):
|
|
76
|
+
"""
|
|
77
|
+
Format a complete value with type tag and optional value.
|
|
78
|
+
|
|
79
|
+
Arguments:
|
|
80
|
+
type_tag: Formatted type tag string
|
|
81
|
+
val: Optional value to display
|
|
82
|
+
value_style: Style sentinel to use for the value
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
Complete formatted string
|
|
86
|
+
"""
|
|
87
|
+
if val is not None:
|
|
88
|
+
return f"{type_tag} {self.print(value_style, str(val), reset)}"
|
|
89
|
+
else:
|
|
90
|
+
return type_tag
|
|
91
|
+
|
|
92
|
+
class XTerm(Text):
|
|
93
|
+
"""ANSI color/style output for terminal."""
|
|
94
|
+
|
|
95
|
+
# ANSI codes
|
|
96
|
+
RESET = '\033[0m'
|
|
97
|
+
BOLD = '\033[1m'
|
|
98
|
+
DIM = '\033[2m'
|
|
99
|
+
|
|
100
|
+
RED = '\033[31m'
|
|
101
|
+
GREEN = '\033[32m'
|
|
102
|
+
YELLOW = '\033[33m'
|
|
103
|
+
BLUE = '\033[34m'
|
|
104
|
+
MAGENTA = '\033[35m'
|
|
105
|
+
CYAN = '\033[36m'
|
|
106
|
+
WHITE = '\033[37m'
|
|
107
|
+
|
|
108
|
+
BRIGHT_RED = '\033[91m'
|
|
109
|
+
BRIGHT_GREEN = '\033[92m'
|
|
110
|
+
BRIGHT_YELLOW = '\033[93m'
|
|
111
|
+
BRIGHT_BLUE = '\033[94m'
|
|
112
|
+
BRIGHT_MAGENTA = '\033[95m'
|
|
113
|
+
BRIGHT_CYAN = '\033[96m'
|
|
114
|
+
|
|
115
|
+
def __init__(self):
|
|
116
|
+
# Map style sentinels to ANSI codes
|
|
117
|
+
self.style_map = {
|
|
118
|
+
reset: self.RESET,
|
|
119
|
+
metadata: self.DIM,
|
|
120
|
+
address: self.DIM,
|
|
121
|
+
type: '',
|
|
122
|
+
value: '',
|
|
123
|
+
string: self.GREEN,
|
|
124
|
+
number: self.CYAN,
|
|
125
|
+
symbol: self.YELLOW,
|
|
126
|
+
method: self.YELLOW, # Same as symbol
|
|
127
|
+
error: self.RED,
|
|
128
|
+
bold: self.BOLD,
|
|
129
|
+
dim: self.DIM,
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
def print(self, *args):
|
|
133
|
+
"""Print arguments, replacing style sentinels with ANSI codes."""
|
|
134
|
+
result = []
|
|
135
|
+
for arg in args:
|
|
136
|
+
if isinstance(arg, Style):
|
|
137
|
+
result.append(self.style_map.get(arg, ''))
|
|
138
|
+
else:
|
|
139
|
+
# If arg has a print_to method, use it
|
|
140
|
+
if hasattr(arg, 'print_to'):
|
|
141
|
+
result.append(arg.print_to(self))
|
|
142
|
+
else:
|
|
143
|
+
result.append(str(arg))
|
|
144
|
+
return "".join(result)
|
|
145
|
+
|
|
146
|
+
# Helper for creating the appropriate terminal based on TTY status
|
|
147
|
+
def create_terminal(from_tty):
|
|
148
|
+
"""Create a terminal instance based on whether we're in a TTY."""
|
|
149
|
+
if from_tty:
|
|
150
|
+
return XTerm()
|
|
151
|
+
else:
|
|
152
|
+
return Text()
|
|
153
|
+
|
|
154
|
+
class Printer:
|
|
155
|
+
"""Printer that combines terminal formatting with recursive printing logic."""
|
|
156
|
+
|
|
157
|
+
def __init__(self, terminal, max_depth, debug_mode=False):
|
|
158
|
+
self.terminal = terminal
|
|
159
|
+
self.max_depth = max_depth
|
|
160
|
+
self.debug_mode = debug_mode
|
|
161
|
+
|
|
162
|
+
def debug(self, message):
|
|
163
|
+
"""Print debug messages only when debug mode is enabled."""
|
|
164
|
+
if self.debug_mode:
|
|
165
|
+
import sys
|
|
166
|
+
print(f"DEBUG: {message}", file=sys.stderr)
|
|
167
|
+
|
|
168
|
+
def print(self, *args):
|
|
169
|
+
"""Print arguments using the terminal's formatting."""
|
|
170
|
+
print(self.terminal.print(*args))
|
|
171
|
+
|
|
172
|
+
def print_indent(self, depth):
|
|
173
|
+
"""Print indentation based on depth."""
|
|
174
|
+
print(" " * depth, end='')
|
|
175
|
+
|
|
176
|
+
def print_with_indent(self, depth, message, end='\n'):
|
|
177
|
+
"""Print a message with proper indentation based on depth."""
|
|
178
|
+
self.print_indent(depth)
|
|
179
|
+
print(message, end=end)
|
|
180
|
+
|
|
181
|
+
def print_key_label(self, depth, index):
|
|
182
|
+
"""Print a consistently formatted key label."""
|
|
183
|
+
self.print_with_indent(depth, f"[{index:>4}] K: ", end='')
|
|
184
|
+
|
|
185
|
+
def print_value_label(self, depth):
|
|
186
|
+
"""Print a consistently formatted value label."""
|
|
187
|
+
self.print_with_indent(depth, f" V: ", end='')
|
|
188
|
+
|
|
189
|
+
def print_item_label(self, depth, index):
|
|
190
|
+
"""Print a consistently formatted array item label."""
|
|
191
|
+
self.print_with_indent(depth, f"[{index:>4}] I: ", end='')
|
|
192
|
+
|
|
193
|
+
def print_value(self, ruby_value, depth):
|
|
194
|
+
"""Print a Ruby value at the given depth."""
|
|
195
|
+
value_int = int(ruby_value)
|
|
196
|
+
self.debug(f"print_value: value=0x{value_int:x}, depth={depth}")
|
|
197
|
+
|
|
198
|
+
# Use interpret to get the appropriate wrapper and let it print itself
|
|
199
|
+
import value
|
|
200
|
+
ruby_object = value.interpret(ruby_value)
|
|
201
|
+
ruby_object.print_recursive(self, depth)
|