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.
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 +200 -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 +479 -0
  13. data/data/toolbox/constants.py +200 -0
  14. data/data/toolbox/context.py +371 -0
  15. data/data/toolbox/debugger/__init__.py +101 -0
  16. data/data/toolbox/debugger/gdb_backend.py +664 -0
  17. data/data/toolbox/debugger/lldb_backend.py +986 -0
  18. data/data/toolbox/fiber.py +877 -0
  19. data/data/toolbox/format.py +205 -0
  20. data/data/toolbox/heap.py +679 -0
  21. data/data/toolbox/init.py +89 -0
  22. data/data/toolbox/print.py +79 -0
  23. data/data/toolbox/rarray.py +116 -0
  24. data/data/toolbox/rbasic.py +99 -0
  25. data/data/toolbox/rbignum.py +48 -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 +88 -0
  30. data/data/toolbox/rhash.py +151 -0
  31. data/data/toolbox/rstring.py +230 -0
  32. data/data/toolbox/rstruct.py +149 -0
  33. data/data/toolbox/rsymbol.py +278 -0
  34. data/data/toolbox/rvalue.py +183 -0
  35. data/data/toolbox/stack.py +620 -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 +0 -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,183 @@
1
+ import sys
2
+ import constants
3
+ import format
4
+
5
+
6
+ import rbasic
7
+ import rfloat
8
+ import rsymbol
9
+ import rstring
10
+ import rarray
11
+ import rhash
12
+ import rstruct
13
+ import rbignum
14
+
15
+ class RImmediate:
16
+ """Wrapper for Ruby immediate values (fixnum, nil, true, false)."""
17
+
18
+ def __init__(self, value):
19
+ self.value = value
20
+ self.val_int = int(value)
21
+
22
+ def __str__(self):
23
+ if self.val_int == 0:
24
+ return "<T_FALSE>"
25
+ elif self.val_int == 0x04 or self.val_int == 0x08:
26
+ return "<T_NIL>"
27
+ elif self.val_int == 0x14:
28
+ return "<T_TRUE>"
29
+ elif (self.val_int & 0x01) != 0:
30
+ # Fixnum - shift right to get actual value
31
+ return str(self.val_int >> 1)
32
+ else:
33
+ # Unknown immediate
34
+ return f"<Immediate:0x{self.val_int:x}>"
35
+
36
+ def print_to(self, terminal):
37
+ """Print this value with formatting to the given terminal."""
38
+ if self.val_int == 0:
39
+ terminal.print_type_tag('T_FALSE')
40
+ elif self.val_int == 0x04 or self.val_int == 0x08:
41
+ terminal.print_type_tag('T_NIL')
42
+ elif self.val_int == 0x14:
43
+ terminal.print_type_tag('T_TRUE')
44
+ elif (self.val_int & 0x01) != 0:
45
+ # Fixnum - shift right to get actual value
46
+ terminal.print_type_tag('T_FIXNUM')
47
+ terminal.print(' ', end='')
48
+ terminal.print(format.number, str(self.val_int >> 1), format.reset, end='')
49
+ else:
50
+ # Unknown immediate
51
+ terminal.print_type_tag('Immediate', self.val_int)
52
+
53
+ def print_recursive(self, printer, depth):
54
+ """Print this immediate value (no recursion needed)."""
55
+ printer.print(self)
56
+
57
+ def is_nil(value):
58
+ """Check if a Ruby VALUE is nil.
59
+
60
+ Arguments:
61
+ value: A GDB value representing a Ruby VALUE
62
+
63
+ Returns:
64
+ True if the value is nil (Qnil), False otherwise
65
+ """
66
+ val_int = int(value)
67
+ # Qnil can be 0x04 or 0x08 depending on Ruby version
68
+ return val_int == 0x04 or val_int == 0x08
69
+
70
+ def is_immediate(value):
71
+ """Check if a Ruby VALUE is an immediate value.
72
+
73
+ Immediate values include fixnum, symbols, nil, true, false.
74
+ They are encoded directly in the VALUE, not as heap objects.
75
+
76
+ Arguments:
77
+ value: A GDB value representing a Ruby VALUE
78
+
79
+ Returns:
80
+ True if the value is immediate, False if it's a heap object
81
+ """
82
+ val_int = int(value)
83
+ # Check for special constants (Qfalse=0, Qnil=0x04/0x08, Qtrue=0x14)
84
+ # or immediate values (fixnum, symbol, flonum) which have low bits set
85
+ return val_int == 0 or (val_int & 0x03) != 0
86
+
87
+ def is_object(value):
88
+ """Check if a Ruby VALUE is a heap object (not immediate).
89
+
90
+ Arguments:
91
+ value: A GDB value representing a Ruby VALUE
92
+
93
+ Returns:
94
+ True if the value is a heap object, False if it's immediate
95
+ """
96
+ return not is_immediate(value)
97
+
98
+ def is_exception(value):
99
+ """Check if a Ruby VALUE is an exception object.
100
+
101
+ Arguments:
102
+ value: A GDB value representing a Ruby VALUE
103
+
104
+ Returns:
105
+ True if the value appears to be an exception object, False otherwise
106
+ """
107
+ if not is_object(value):
108
+ return False
109
+
110
+ try:
111
+ # Check if it's a T_OBJECT or T_DATA (exceptions can be either)
112
+ basic = value.cast(constants.type_struct("struct RBasic").pointer())
113
+ flags = int(basic.dereference()['flags'])
114
+ type_flag = flags & constants.type("RUBY_T_MASK")
115
+
116
+ # Exceptions are typically T_OBJECT, but could also be T_DATA
117
+ # We can't reliably determine if it's an exception without checking the class hierarchy
118
+ # So we just check if it's an object type that could be an exception
119
+ t_object = constants.type("RUBY_T_OBJECT")
120
+ t_data = constants.type("RUBY_T_DATA")
121
+
122
+ return type_flag == t_object or type_flag == t_data
123
+ except Exception:
124
+ return False
125
+
126
+ def interpret(value):
127
+ """Interpret a Ruby VALUE and return the appropriate typed object.
128
+
129
+ This is a factory function that examines the value and returns the
130
+ most specific type wrapper available (RString, RArray, RHash, etc.),
131
+ or RBasic as a fallback for unhandled types.
132
+
133
+ For immediate values (fixnum, flonum, symbol, nil, true, false), it returns
134
+ the appropriate wrapper (RImmediate, RFloat, RSymbol).
135
+
136
+ Arguments:
137
+ value: A GDB value representing a Ruby VALUE
138
+
139
+ Returns:
140
+ An instance of the appropriate type class (never None)
141
+ """
142
+ val_int = int(value)
143
+
144
+ # Check for immediate flonum (must be before fixnum check)
145
+ if rfloat.is_flonum(value):
146
+ return rfloat.RFloat(value)
147
+
148
+ # Check if it's a symbol (immediate or heap)
149
+ if rsymbol.is_symbol(value):
150
+ return rsymbol.RSymbol(value)
151
+
152
+ # Handle special constants and fixnum (anything with low bits set)
153
+ if val_int == 0 or val_int == 0x04 or val_int == 0x08 or val_int == 0x14 or (val_int & 0x01) != 0:
154
+ return RImmediate(value)
155
+
156
+ # It's a heap object, examine its type
157
+ try:
158
+ basic = value.cast(constants.type_struct("struct RBasic").pointer())
159
+ flags = int(basic.dereference()['flags'])
160
+ type_flag = flags & constants.type("RUBY_T_MASK")
161
+
162
+ # Map type flags to their corresponding factory functions
163
+ if type_flag == constants.type("RUBY_T_STRING"):
164
+ return rstring.RString(value)
165
+ elif type_flag == constants.type("RUBY_T_ARRAY"):
166
+ return rarray.RArray(value)
167
+ elif type_flag == constants.type("RUBY_T_HASH"):
168
+ return rhash.RHash(value)
169
+ elif type_flag == constants.type("RUBY_T_STRUCT"):
170
+ return rstruct.RStruct(value)
171
+ elif type_flag == constants.type("RUBY_T_SYMBOL"):
172
+ return rsymbol.RSymbol(value)
173
+ elif type_flag == constants.type("RUBY_T_FLOAT"):
174
+ return rfloat.RFloat(value)
175
+ elif type_flag == constants.type("RUBY_T_BIGNUM"):
176
+ return rbignum.RBignum(value)
177
+ else:
178
+ # Unknown type - return generic RBasic
179
+ return rbasic.RBasic(value)
180
+ except Exception as e:
181
+ # If we can't examine it, return a generic wrapper
182
+ print(f"DEBUG interpret: exception {e}, returning RBasic", file=sys.stderr)
183
+ return rbasic.RBasic(value)