toolbox 0.1.4 → 0.2.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.
Files changed (98) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/bake/ruby/gdb.rb +135 -0
  4. data/bake/toolbox/gdb.rb +137 -0
  5. data/bake/toolbox/lldb.rb +137 -0
  6. data/context/fiber-debugging.md +171 -0
  7. data/context/getting-started.md +178 -0
  8. data/context/heap-debugging.md +351 -0
  9. data/context/index.yaml +28 -0
  10. data/context/object-inspection.md +208 -0
  11. data/context/stack-inspection.md +188 -0
  12. data/data/toolbox/command.py +254 -0
  13. data/data/toolbox/constants.py +200 -0
  14. data/data/toolbox/context.py +295 -0
  15. data/data/toolbox/debugger/__init__.py +99 -0
  16. data/data/toolbox/debugger/gdb_backend.py +595 -0
  17. data/data/toolbox/debugger/lldb_backend.py +885 -0
  18. data/data/toolbox/fiber.py +885 -0
  19. data/data/toolbox/format.py +200 -0
  20. data/data/toolbox/heap.py +669 -0
  21. data/data/toolbox/init.py +85 -0
  22. data/data/toolbox/object.py +84 -0
  23. data/data/toolbox/rarray.py +124 -0
  24. data/data/toolbox/rbasic.py +103 -0
  25. data/data/toolbox/rbignum.py +52 -0
  26. data/data/toolbox/rclass.py +136 -0
  27. data/data/toolbox/readme.md +214 -0
  28. data/data/toolbox/rexception.py +150 -0
  29. data/data/toolbox/rfloat.py +98 -0
  30. data/data/toolbox/rhash.py +159 -0
  31. data/data/toolbox/rstring.py +234 -0
  32. data/data/toolbox/rstruct.py +157 -0
  33. data/data/toolbox/rsymbol.py +302 -0
  34. data/data/toolbox/stack.py +630 -0
  35. data/data/toolbox/value.py +183 -0
  36. data/lib/toolbox/gdb.rb +21 -0
  37. data/lib/toolbox/lldb.rb +21 -0
  38. data/lib/toolbox/version.rb +7 -1
  39. data/lib/toolbox.rb +9 -24
  40. data/license.md +21 -0
  41. data/readme.md +64 -0
  42. data/releases.md +9 -0
  43. data.tar.gz.sig +2 -0
  44. metadata +95 -165
  45. metadata.gz.sig +0 -0
  46. data/Rakefile +0 -61
  47. data/lib/dirs.rb +0 -9
  48. data/lib/toolbox/config.rb +0 -211
  49. data/lib/toolbox/default_controller.rb +0 -393
  50. data/lib/toolbox/helpers.rb +0 -11
  51. data/lib/toolbox/rendering.rb +0 -413
  52. data/lib/toolbox/searching.rb +0 -85
  53. data/lib/toolbox/session_params.rb +0 -63
  54. data/lib/toolbox/sorting.rb +0 -74
  55. data/locale/de/LC_MESSAGES/toolbox.mo +0 -0
  56. data/public/images/add.png +0 -0
  57. data/public/images/arrow_down.gif +0 -0
  58. data/public/images/arrow_up.gif +0 -0
  59. data/public/images/close.png +0 -0
  60. data/public/images/edit.gif +0 -0
  61. data/public/images/email.png +0 -0
  62. data/public/images/page.png +0 -0
  63. data/public/images/page_acrobat.png +0 -0
  64. data/public/images/page_add.png +0 -0
  65. data/public/images/page_copy.png +0 -0
  66. data/public/images/page_delete.png +0 -0
  67. data/public/images/page_edit.png +0 -0
  68. data/public/images/page_excel.png +0 -0
  69. data/public/images/page_list.png +0 -0
  70. data/public/images/page_save.png +0 -0
  71. data/public/images/page_word.png +0 -0
  72. data/public/images/remove.png +0 -0
  73. data/public/images/show.gif +0 -0
  74. data/public/images/spinner.gif +0 -0
  75. data/public/javascripts/popup.js +0 -498
  76. data/public/javascripts/toolbox.js +0 -18
  77. data/public/stylesheets/context_menu.css +0 -168
  78. data/public/stylesheets/popup.css +0 -30
  79. data/public/stylesheets/toolbox.css +0 -107
  80. data/view/toolbox/_collection.html.erb +0 -24
  81. data/view/toolbox/_collection_header.html.erb +0 -7
  82. data/view/toolbox/_context_menu.html.erb +0 -17
  83. data/view/toolbox/_dialogs.html.erb +0 -6
  84. data/view/toolbox/_form.html.erb +0 -30
  85. data/view/toolbox/_form_collection_row.html.erb +0 -18
  86. data/view/toolbox/_form_fieldset.html.erb +0 -30
  87. data/view/toolbox/_form_fieldset_row.html.erb +0 -19
  88. data/view/toolbox/_list.html.erb +0 -25
  89. data/view/toolbox/_list_row.html.erb +0 -10
  90. data/view/toolbox/_menu.html.erb +0 -7
  91. data/view/toolbox/_search_field.html.erb +0 -8
  92. data/view/toolbox/_show.html.erb +0 -12
  93. data/view/toolbox/_show_collection_row.html.erb +0 -6
  94. data/view/toolbox/_show_fieldset.html.erb +0 -21
  95. data/view/toolbox/edit.html.erb +0 -5
  96. data/view/toolbox/index.html.erb +0 -3
  97. data/view/toolbox/new.html.erb +0 -9
  98. data/view/toolbox/show.html.erb +0 -39
@@ -0,0 +1,178 @@
1
+ # Getting Started
2
+
3
+ This guide explains how to install and use Toolbox for debugging Ruby programs and core dumps with GDB or LLDB.
4
+
5
+ ## Installation
6
+
7
+ Install the gem:
8
+
9
+ ~~~ bash
10
+ $ gem install toolbox
11
+ ~~~
12
+
13
+ ### Installing GDB Extensions
14
+
15
+ Install the GDB extensions (automatically adds to `~/.gdbinit`):
16
+
17
+ ~~~ bash
18
+ $ bake toolbox:gdb:install
19
+ ~~~
20
+
21
+ This adds a single line to your `~/.gdbinit` that sources the extensions from the gem's data directory. The extensions will then load automatically every time you start GDB.
22
+
23
+ To install to a custom `.gdbinit` location:
24
+
25
+ ~~~ bash
26
+ $ bake toolbox:gdb:install gdbinit=/path/to/custom/gdbinit
27
+ ~~~
28
+
29
+ ### Installing LLDB Extensions
30
+
31
+ Install the LLDB extensions (automatically adds to `~/.lldbinit`):
32
+
33
+ ~~~ bash
34
+ $ bake toolbox:lldb:install
35
+ ~~~
36
+
37
+ This adds a command script import line to your `~/.lldbinit` that loads the extensions from the gem's data directory. The extensions will then load automatically every time you start LLDB.
38
+
39
+ To install to a custom `.lldbinit` location:
40
+
41
+ ~~~ bash
42
+ $ bake toolbox:lldb:install lldbinit=/path/to/custom/lldbinit
43
+ ~~~
44
+
45
+ ### Verifying Installation
46
+
47
+ Check GDB installation status:
48
+
49
+ ~~~ bash
50
+ $ bake toolbox:gdb:info
51
+ Ruby Toolbox GDB Extensions v0.1.0
52
+ Status: ✓ Installed
53
+ ~~~
54
+
55
+ Check LLDB installation status:
56
+
57
+ ~~~ bash
58
+ $ bake toolbox:lldb:info
59
+ Ruby Toolbox LLDB Extensions v0.1.0
60
+ Status: ✓ Installed
61
+ ~~~
62
+
63
+ Test that extensions load automatically:
64
+
65
+ ~~~ bash
66
+ $ gdb --batch -ex "help rb-object-print"
67
+ Recursively print Ruby hash and array structures...
68
+ ~~~
69
+
70
+ ### Uninstalling
71
+
72
+ To remove the GDB extensions:
73
+
74
+ ~~~ bash
75
+ $ bake toolbox:gdb:uninstall
76
+ ~~~
77
+
78
+ To remove the LLDB extensions:
79
+
80
+ ~~~ bash
81
+ $ bake toolbox:lldb:uninstall
82
+ ~~~
83
+
84
+ This removes the source line from your `~/.gdbinit`.
85
+
86
+ ## Core Concepts
87
+
88
+ Ruby GDB provides specialized commands for debugging Ruby at multiple levels:
89
+
90
+ - **Context Setup** (`rb-context`) - Get current execution context and set up convenience variables
91
+ - **Object Inspection** (`rb-object-print`) - View Ruby objects, hashes, arrays, and structs with proper formatting
92
+ - **Fiber Debugging** (`rb-fiber-*`) - Scan heap for fibers, inspect state, and switch contexts
93
+ - **Stack Analysis** (`rb-stack-trace`) - Examine combined VM (Ruby) and C (native) stack frames
94
+ - **Heap Navigation** (`rb-heap-scan`) - Scan the Ruby heap to find objects by type
95
+
96
+ ## Quick Start
97
+
98
+ ### Debugging a Running Process
99
+
100
+ Start your Ruby program under GDB:
101
+
102
+ ~~~ bash
103
+ $ gdb --args ruby my_script.rb
104
+ ~~~
105
+
106
+ Set a breakpoint and run:
107
+
108
+ ~~~
109
+ (gdb) break rb_vm_exec
110
+ (gdb) run
111
+ ~~~
112
+
113
+ Once stopped, use Ruby debugging commands:
114
+
115
+ ~~~
116
+ (gdb) rb-stack-trace # Show combined Ruby/C backtrace
117
+ (gdb) rb-fiber-scan-heap # Scan heap for fibers
118
+ (gdb) rb-heap-scan --type RUBY_T_STRING --limit 5 # Find strings
119
+ ~~~
120
+
121
+ ### Debugging a Core Dump
122
+
123
+ When your Ruby program crashes, you can analyze the core dump:
124
+
125
+ ~~~ bash
126
+ $ gdb ruby core.dump
127
+ ~~~
128
+
129
+ Diagnose the issue (extensions load automatically if installed):
130
+
131
+ ~~~
132
+ (gdb) rb-fiber-scan-heap # Scan heap for all fibers
133
+ (gdb) rb-fiber-scan-stack-trace-all # Show backtraces for all fibers
134
+ (gdb) rb-fiber-scan-switch 0 # Switch to main fiber
135
+ (gdb) rb-object-print $errinfo --depth 2 # Print exception (now $errinfo is set)
136
+ (gdb) rb-heap-scan --type RUBY_T_HASH --limit 10 # Find hashes
137
+ ~~~
138
+
139
+ ## Common Workflows
140
+
141
+ ### Inspecting Exception Objects
142
+
143
+ When a Ruby exception occurs, you can inspect it in detail:
144
+
145
+ ~~~
146
+ (gdb) break rb_exc_raise
147
+ (gdb) run
148
+ (gdb) rb-context
149
+ (gdb) rb-object-print $errinfo --depth 2
150
+ ~~~
151
+
152
+ This shows the exception class, message, and any nested structures. The `rb-context` command displays the current execution context and sets up `$ec`, `$cfp`, and `$errinfo` convenience variables.
153
+
154
+ ### Debugging Fiber Issues
155
+
156
+ When working with fibers, you often need to see what each fiber is doing:
157
+
158
+ ~~~
159
+ (gdb) rb-fiber-scan-heap # Scan heap for all fibers
160
+ (gdb) rb-fiber-scan-stack-trace-all # Show backtraces for all fibers
161
+ (gdb) rb-fiber-scan-switch 5 # Switch GDB to fiber #5's context
162
+ (gdb) rb-stack-trace # Now shows fiber's combined backtrace
163
+ ~~~
164
+
165
+ ### Examining Complex Data Structures
166
+
167
+ Ruby hashes and arrays can contain nested structures:
168
+
169
+ ~~~
170
+ (gdb) rb-object-print $some_hash --depth 2
171
+ <T_HASH@...>
172
+ [ 0] K: <T_SYMBOL> :name
173
+ V: <T_STRING@...> "Alice"
174
+ [ 1] K: <T_SYMBOL> :age
175
+ V: <T_FIXNUM> 30
176
+ ~~~
177
+
178
+ The `--depth` flag controls how deep to recurse into nested objects.
@@ -0,0 +1,351 @@
1
+ # Heap Debugging
2
+
3
+ This guide explains how to navigate Ruby's heap to find objects, diagnose memory issues, and understand object relationships.
4
+
5
+ ## Why Heap Debugging Matters
6
+
7
+ Ruby's garbage collector manages thousands to millions of objects across heap pages. When debugging memory leaks, performance issues, or trying to find specific objects, you need to navigate this heap efficiently. Standard GDB cannot understand Ruby's object layout or page structure, making manual heap inspection tedious and error-prone.
8
+
9
+ Use heap debugging when you need:
10
+
11
+ - **Find leaked objects**: Locate objects that should have been garbage collected
12
+ - **Discover fiber instances**: Find all fibers in a crashed or hung application
13
+ - **Track object relationships**: See what objects reference others
14
+ - **Diagnose memory bloat**: Understand what types of objects consume memory
15
+
16
+ ## Heap Structure Overview
17
+
18
+ Ruby's heap is organized as:
19
+
20
+ 1. **Heap Pages**: Fixed-size pages allocated from the system
21
+ 2. **Slots**: Each page contains fixed-size slots for objects
22
+ 3. **Objects**: Ruby objects (RBasic, RHash, RArray, etc.) stored in slots
23
+ 4. **Object Space**: The global heap manager (`objspace`)
24
+
25
+ ## Scanning the Heap
26
+
27
+ ### Finding Objects by Type
28
+
29
+ Scan the heap for specific types of Ruby objects:
30
+
31
+ ~~~
32
+ (gdb) rb-heap-scan --type RUBY_T_STRING --limit 10
33
+ Scanning heap for type 0x05, limit=10...
34
+
35
+ Found 10 object(s):
36
+
37
+ [0] $heap0 = <T_STRING@...> "..."
38
+ [1] $heap1 = <T_STRING@...> "..."
39
+ ...
40
+ [9] $heap9 = <T_STRING@...> "..."
41
+
42
+ Objects saved in $heap0 through $heap9
43
+ Next scan address saved to $heap: 0x...
44
+ Run 'rb-heap-scan --from $heap ...' for next page
45
+ ~~~
46
+
47
+ ### Finding Fibers
48
+
49
+ Find all fiber objects:
50
+
51
+ ~~~
52
+ (gdb) rb-fiber-scan-heap
53
+ Scanning heap for Fiber objects...
54
+ Checked 45000 objects, found 12 fiber(s)...
55
+
56
+ Found 12 fiber(s):
57
+
58
+ Fiber #0: <T_DATA@...> → <struct rb_fiber_struct@...>
59
+ Status: SUSPENDED
60
+ Stack: <void *@...>
61
+ VM Stack: <VALUE *@...>
62
+ CFP: <rb_control_frame_t@...>
63
+ ...
64
+ ~~~
65
+
66
+ This uses a specialized scanner optimized for fibers.
67
+
68
+ ### How Heap Scanning Works
69
+
70
+ The scanner:
71
+
72
+ 1. Accesses `ruby_current_vm_ptr->gc->objspace`
73
+ 2. Iterates through `heap_pages->sorted->data[]`
74
+ 3. For each page, checks `total_slots` objects
75
+ 4. Identifies objects by their `flags` field (bits 0-4 = type)
76
+ 5. Filters for specific types if `--type` is specified
77
+
78
+ ### Common Types
79
+
80
+ Ruby type constants and their numeric values:
81
+
82
+ ~~~
83
+ RUBY_T_STRING = 0x05 # Strings
84
+ RUBY_T_ARRAY = 0x07 # Arrays
85
+ RUBY_T_HASH = 0x08 # Hashes
86
+ RUBY_T_DATA = 0x0c # Data objects (like Fibers)
87
+ RUBY_T_OBJECT = 0x01 # Generic objects
88
+ ~~~
89
+
90
+ Examples:
91
+
92
+ ~~~
93
+ (gdb) rb-heap-scan --type RUBY_T_STRING --limit 20
94
+ (gdb) rb-heap-scan --type 0x08 --limit 10 # Same as RUBY_T_HASH
95
+ (gdb) rb-heap-scan --limit 100 # All types
96
+ ~~~
97
+
98
+ ### Pagination
99
+
100
+ Continue scanning from where you left off:
101
+
102
+ ~~~
103
+ (gdb) rb-heap-scan --type RUBY_T_STRING --limit 10
104
+ Scanning heap for type 0x05, limit=10...
105
+
106
+ Found 10 object(s):
107
+ [0] $heap0 = <T_STRING@...> "..."
108
+ ...
109
+ Objects saved in $heap0 through $heap9
110
+ Next scan address saved to $heap: 0x...
111
+
112
+ (gdb) rb-heap-scan --type RUBY_T_STRING --limit 10 --from $heap
113
+ Scanning heap for type 0x05, limit=10...
114
+ Starting from saved position: 0x...
115
+
116
+ Found 10 object(s):
117
+ [0] $heap0 = <T_STRING@...> "..."
118
+ ...
119
+ ~~~
120
+
121
+ ## Understanding Object Layout
122
+
123
+ ### Object Headers (RBasic)
124
+
125
+ Every Ruby object starts with:
126
+
127
+ ~~~ruby
128
+ struct RBasic {
129
+ VALUE flags; # Type and flag information
130
+ VALUE klass; # Object's class
131
+ }
132
+ ~~~
133
+
134
+ The `flags` field encodes:
135
+ - Object type (bits 0-4): T_STRING, T_HASH, T_ARRAY, etc.
136
+ - GC flags (bit 5-11): Mark bits, frozen status, etc.
137
+ - Type-specific flags (bits 12+): Embedded vs heap, size info, etc.
138
+
139
+ ### Type Detection
140
+
141
+ Check an object's type:
142
+
143
+ ~~~
144
+ (gdb) set $obj = (VALUE)0x7f8a1c888888
145
+ (gdb) set $basic = (struct RBasic *)$obj
146
+ (gdb) p/x $basic->flags
147
+ $1 = 0x20040005
148
+
149
+ (gdb) p/x $basic->flags & 0x1f
150
+ $2 = 0x5 # T_STRING (0x05)
151
+ ~~~
152
+
153
+ Or use Ruby commands:
154
+
155
+ ~~~python
156
+ obj_type = flags & 0x1f
157
+ type_names = {
158
+ 0x05: "T_STRING",
159
+ 0x07: "T_ARRAY",
160
+ 0x08: "T_HASH",
161
+ 0x0c: "T_DATA",
162
+ ...
163
+ }
164
+ ~~~
165
+
166
+ ## Practical Examples
167
+
168
+ ### Finding All Objects of a Type
169
+
170
+ Scan for all string objects (requires custom script):
171
+
172
+ ~~~python
173
+ python
174
+ for obj, flags in iterate_heap():
175
+ if (flags & 0x1f) == 0x05: # T_STRING
176
+ print(f"String at {obj}")
177
+ end
178
+ ~~~
179
+
180
+ ### Locating Large Arrays
181
+
182
+ Find arrays consuming significant memory:
183
+
184
+ ~~~python
185
+ python
186
+ for obj, flags in iterate_heap():
187
+ if (flags & 0x1f) == 0x07: # T_ARRAY
188
+ rarray = obj.cast(gdb.lookup_type("struct RArray").pointer())
189
+ if (flags & (1 << 12)) == 0: # Heap array (not embedded)
190
+ length = int(rarray["as"]["heap"]["len"])
191
+ if length > 1000:
192
+ print(f"Large array at {obj}: {length} elements")
193
+ end
194
+ ~~~
195
+
196
+ ### Finding Objects by Content
197
+
198
+ Search for strings containing specific text:
199
+
200
+ ~~~python
201
+ python
202
+ import gdb
203
+
204
+ def find_strings_containing(search_text):
205
+ """Find all Ruby strings containing specific text"""
206
+ matches = []
207
+ for obj, flags in iterate_heap():
208
+ if (flags & 0x1f) == 0x05: # T_STRING
209
+ try:
210
+ rstring = obj.cast(gdb.lookup_type("struct RString").pointer())
211
+ length = int(rstring["len"])
212
+
213
+ # Read string content (simplified)
214
+ if length < 1000: # Reasonable size
215
+ # ... (read string bytes) ...
216
+ if search_text in string_content:
217
+ matches.append(obj)
218
+ except:
219
+ pass
220
+ return matches
221
+ end
222
+ ~~~
223
+
224
+ ## Memory Analysis
225
+
226
+ ### Heap Page Statistics
227
+
228
+ Understand heap organization:
229
+
230
+ ~~~
231
+ (gdb) p ruby_current_vm_ptr->gc->objspace->heap_pages->allocated_pages
232
+ $1 = 1250 # Total pages allocated
233
+
234
+ (gdb) p ruby_current_vm_ptr->gc->objspace->heap_pages->sorted->meta->length
235
+ $2 = 1250 # Accessible pages
236
+
237
+ # Average objects per page:
238
+ (gdb) p 67890 / 1250
239
+ $3 = 54 # ~54 objects per page
240
+ ~~~
241
+
242
+ ### Object Slot Details
243
+
244
+ Examine a specific heap page:
245
+
246
+ ~~~
247
+ (gdb) set $page = ruby_current_vm_ptr->gc->objspace->heap_pages->sorted->data[0]
248
+ (gdb) p $page->start # First object address
249
+ $4 = 0x7f8a1c000000
250
+
251
+ (gdb) p $page->total_slots # Objects in this page
252
+ $5 = 64
253
+
254
+ (gdb) p $page->slot_size # Bytes per slot
255
+ $6 = 40
256
+ ~~~
257
+
258
+ ### Memory Consumption
259
+
260
+ Calculate memory usage by type:
261
+
262
+ ~~~python
263
+ python
264
+ type_counts = {}
265
+ type_memory = {}
266
+
267
+ for obj, flags in iterate_heap():
268
+ obj_type = flags & 0x1f
269
+ type_counts[obj_type] = type_counts.get(obj_type, 0) + 1
270
+ # Each object consumes at minimum one slot
271
+ type_memory[obj_type] = type_memory.get(obj_type, 0) + 40 # slot_size
272
+
273
+ for obj_type in sorted(type_counts.keys()):
274
+ count = type_counts[obj_type]
275
+ memory_kb = type_memory[obj_type] / 1024
276
+ print(f"Type 0x{obj_type:02x}: {count:6} objects, {memory_kb:8.1f} KB")
277
+ end
278
+ ~~~
279
+
280
+ ## Advanced Techniques
281
+
282
+ ### Custom Heap Iterators
283
+
284
+ The fiber scanning code provides a reusable heap iterator:
285
+
286
+ ~~~python
287
+ python
288
+ # In your custom GDB script:
289
+ from fiber import RubyFiberDebug
290
+
291
+ debug = RubyFiberDebug()
292
+ if debug.initialize():
293
+ for obj, flags in debug.iterate_heap():
294
+ # Your custom logic here
295
+ pass
296
+ end
297
+ ~~~
298
+
299
+ ### Finding Objects by Reference
300
+
301
+ Locate what holds a reference to an object:
302
+
303
+ ~~~python
304
+ python
305
+ target_address = 0x7f8a1c888888
306
+
307
+ for obj, flags in iterate_heap():
308
+ obj_type = flags & 0x1f
309
+
310
+ # Check if this is a hash
311
+ if obj_type == 0x08:
312
+ rhash = obj.cast(gdb.lookup_type("struct RHash").pointer())
313
+ # ... iterate hash entries ...
314
+ # ... check if any value == target_address ...
315
+
316
+ # Check if this is an array
317
+ elif obj_type == 0x07:
318
+ # ... iterate array elements ...
319
+ end
320
+ ~~~
321
+
322
+ This helps track down unexpected object retention.
323
+
324
+ ### Heap Fragmentation Analysis
325
+
326
+ Check how objects are distributed across pages:
327
+
328
+ ~~~python
329
+ python
330
+ page_utilization = []
331
+
332
+ objspace = gdb.parse_and_eval("ruby_current_vm_ptr->gc->objspace")
333
+ allocated_pages = int(objspace["heap_pages"]["allocated_pages"])
334
+
335
+ for i in range(allocated_pages):
336
+ page = objspace["heap_pages"]["sorted"]["data"][i]
337
+ total_slots = int(page["total_slots"])
338
+
339
+ # Count non-free objects
340
+ used_slots = 0
341
+ # ... iterate and count ...
342
+
343
+ utilization = (used_slots / total_slots) * 100
344
+ page_utilization.append(utilization)
345
+
346
+ average = sum(page_utilization) / len(page_utilization)
347
+ print(f"Average page utilization: {average:.1f}%")
348
+ end
349
+ ~~~
350
+
351
+ Low utilization indicates fragmentation.
@@ -0,0 +1,28 @@
1
+ # Automatically generated context index for Utopia::Project guides.
2
+ # Do not edit then files in this directory directly, instead edit the guides and then run `bake utopia:project:agent:context:update`.
3
+ ---
4
+ description: Ruby debugging toolbox for GDB and LLDB
5
+ metadata:
6
+ documentation_uri: https://socketry.github.io/toolbox/
7
+ source_code_uri: https://github.com/socketry/toolbox
8
+ files:
9
+ - path: getting-started.md
10
+ title: Getting Started
11
+ description: This guide explains how to install and use Toolbox for debugging Ruby
12
+ programs and core dumps with GDB or LLDB.
13
+ - path: object-inspection.md
14
+ title: Object Inspection
15
+ description: This guide explains how to use `rb-object-print` to inspect Ruby objects,
16
+ hashes, arrays, and structs in GDB.
17
+ - path: stack-inspection.md
18
+ title: Stack Inspection
19
+ description: This guide explains how to inspect both Ruby VM stacks and native C
20
+ stacks when debugging Ruby programs.
21
+ - path: fiber-debugging.md
22
+ title: Fiber Debugging
23
+ description: This guide explains how to debug Ruby fibers using GDB, including inspecting
24
+ fiber state, backtraces, and switching between fiber contexts.
25
+ - path: heap-debugging.md
26
+ title: Heap Debugging
27
+ description: This guide explains how to navigate Ruby's heap to find objects, diagnose
28
+ memory issues, and understand object relationships.