-
Notifications
You must be signed in to change notification settings - Fork 86
/
Copy pathgdb-macros
416 lines (381 loc) · 12.8 KB
/
gdb-macros
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
#**************************************************************************
#* *
#* OCaml *
#* *
#* Damien Doligez, Jane Street Group, LLC *
#* *
#* Copyright 2015 Institut National de Recherche en Informatique et *
#* en Automatique. *
#* *
#* All rights reserved. This file is distributed under the terms of *
#* the GNU Lesser General Public License version 2.1, with the *
#* special exception on linking described in the file LICENSE. *
#* *
#**************************************************************************
# A set of macros for low-level debugging of OCaml programs and of the
# OCaml runtime itself (both native and byte-code).
# Advice to future developers: rewrite this in Python which will be
# faster, more reliable, and more maintainable. See also gdb_ocamlrun.py
# This file should be loaded in gdb with [ source gdb-macros ].
# It defines a few related commands:
#
# Usage:
# [caml <value>]
# If <value> is an OCaml value, this will display it in a low-level
# but legible format, including the header information.
#
# [caml-next]
# If the most recent value shown with "caml" is a heap block,
# this will describe the following block.
#
# [caml-field <N>]
# If the most recent value shown with "caml" is a heap block,
# this will describe the Nth field in that block.
set $caml_word_size = sizeof(char *)
set $caml_word_bits = 8 * $caml_word_size
set $caml_pool_size = 4096 * $caml_word_size
if $caml_word_size == 8
set $caml_unalloc_mask = 0xFF00FFFFFF00FFFF
set $caml_unalloc_value = 0xD700D7D7D700D6D7
else
set $caml_unalloc_mask = 0xFF00FFFF
set $caml_unalloc_value = 0xD700D6D7
end
# `caml header item` Displays information about the header of a Caml
# block `item`, with no new-line.
define caml_header
set $hd = * (unsigned long *) ($arg0 - $caml_word_size)
set $tag = $hd & 0xFF
set $color = $hd & (3 << 8)
set $size = $hd >> 10
if $size <= 0 || $size >= 0x1000000000000
if ($hd & $caml_unalloc_mask) == $caml_unalloc_value
printf "[UNALLOCATED MEMORY]"
else
if !$hd
printf "[** fragment **] 0x%lx", $hd
else
printf "[** invalid header **] 0x%lx", $hd
end
end
else
printf "["
if $color == caml_global_heap_state.MARKED
printf "marked "
end
if $color == caml_global_heap_state.UNMARKED
printf "unmarked "
end
if $color == caml_global_heap_state.GARBAGE
printf "garbage "
end
if $color == 3 << 8
printf "not markable "
end
if $tag < 244
printf "tag %d ", $tag
end
if $tag == 244
printf "Forcing "
end
if $tag == 245
printf "Continuation "
end
if $tag == 246
printf "Lazy "
end
if $tag == 247
printf "Closure "
end
if $tag == 248
printf "Object "
end
if $tag == 249
printf "Infix "
end
if $tag == 250
printf "Forward "
end
if $tag == 251
printf "Abstract "
end
if $tag == 252
printf "String "
end
if $tag == 253
printf "Double "
end
if $tag == 254
printf "Double_array "
end
if $tag == 255
printf "Custom "
end
printf "%lu]", $size
end
end
# Various caml_search_* functions which understand the layout of the
# Caml heap. Main driver function is "caml_search". This is slow and
# would benefit from being rewritten in a faster or more capable
# language (e.g. Python). To debug the heap searching itself, set
# $caml_search_debug=1.
# `caml_search_pools name pool item` searches the pool list from
# `pool` onwards for the block `item`. If found, it outputs `FOUND`
# and a description of the pool where it was found. If
# $caml_search_debug is set, it also describes all the pools on the
# list. `name` is a string describing the pool list.
define caml_search_pools
set $pool = $arg1
while $pool && ($caml_search_debug || !$found)
set $found_here = 0
if ($arg2 >= (char*)($pool+1)) && ($arg2 < (char*)$pool + $caml_pool_size)
printf "FOUND"
set $found_here = 1
set $found = 1
end
if $caml_search_debug || $found_here
printf " domain %d %s pool %lx-%lx sizeclass %d(%d)", \
$domain_index, $arg0, $pool, ((char*)$pool)+$caml_pool_size, \
$pool->sz, wsize_sizeclass[$pool->sz]
if $caml_search_debug
printf "\n"
end
end
set $pool = $pool->next
end
end
# `caml_search_large name large item` searches the large block list
# from `large` onwards for the block `item`. If found, it outputs
# `FOUND` and a description of the large block where it was found. If
# $caml_search_debug is set, it also describes all the large blocks
# on the list. `name` is a string describing the large object list.
define caml_search_large
set $large = $arg1
while $large && ($caml_search_debug || !$found)
set $large_hd = * (unsigned long *)($large+1)
set $large_size = ((($large_hd) >> 10)+1)*sizeof(unsigned long)
set $large_end = ((char*)($large+1))+$large_size
set $found_here = 0
if ($arg2 > (char*)$large) && ($arg2 < $large_end)
printf "FOUND"
set $found_here = 1
set $found = 1
end
if $caml_search_debug || $found_here
printf " domain %d %s large %lx-%lx? (size %d?)", \
$domain_index, $arg0, $large, $large_end, $large_size
if $caml_search_debug
printf "\n"
end
end
set $large = $large->next
end
end
# `caml_search_heap_state state item` searches the pool and large
# object lists in the caml_heap_state `state` for the block `item`.
# If found, it outputs `FOUND` and a description of the zone where it
# was found. If $caml_search_debug is set, it also describes all the
# areas searched.
define caml_search_heap_state
set $heap_state = $arg0
set $NUM_SIZECLASSES = sizeof($heap_state->avail_pools)/ \
sizeof($heap_state->avail_pools[0])
set $sizeclass = 0
while $sizeclass < $NUM_SIZECLASSES && ($caml_search_debug || !$found)
caml_search_pools "avail" $heap_state->avail_pools[$sizeclass] $arg1
caml_search_pools "full" $heap_state->full_pools[$sizeclass] $arg1
caml_search_pools "unswept avail" \
$heap_state->unswept_avail_pools[$sizeclass] $arg1
caml_search_pools "unswept full" \
$heap_state->unswept_full_pools[$sizeclass] $arg1
set $sizeclass = $sizeclass + 1
end
caml_search_large "swept" $heap_state->swept_large $arg1
caml_search_large "unswept" $heap_state->unswept_large $arg1
end
# `caml_search item` searches the entire Caml heap for `item` and
# outputs text describing the location, where it was found, with no
# new-line.
define caml_search
set $Max_domains = sizeof(all_domains)/sizeof(all_domains[0])
set $domain_index = 0
set $found = 0
while $domain_index < $Max_domains && !$found
set $domain = all_domains + $domain_index
if $domain->state != 0
if $caml_search_debug
printf "domain %d minor %lx-%lx\n", \
$domain_index, \
$domain->state->young_start, $domain->state->young_end
end
if $arg0 >= $domain->state->young_start && \
$arg0 < $domain->state->young_end
printf "FOUND young (domain %d)", $domain_index
set $found = 1
end
if $caml_search_debug || !$found
caml_search_heap_state $domain->state->shared_heap $arg0
end
end
set $domain_index = $domain_index + 1
end
if $caml_search_debug
printf "Global (orphaned) heap:\n"
end
if $caml_search_debug || !$found
set $sizeclass = 0
set $domain_index = -1
while $sizeclass < $NUM_SIZECLASSES && ($caml_search_debug || !$found)
caml_search_pools "global avail" \
pool_freelist.global_avail_pools[$sizeclass] $arg0
caml_search_pools "global full" \
pool_freelist.global_full_pools[$sizeclass] $arg0
set $sizeclass = $sizeclass + 1
end
caml_search_large "global large" pool_freelist.global_large $arg0
end
set $caml_search_result = $found
if !$caml_search_result
printf "not on Caml heap"
end
end
# `caml_int item` describes `item`, with no new line, on the
# assumption that it's a Caml (tagged) integer.
define caml_int
if ($arg0 & $caml_unalloc_mask) == $caml_unalloc_value
printf "UNALLOCATED MEMORY"
else
printf "INT %ld", ($arg0 >> 1)
end
if ($arg0 & 0xFF) == 0xF9 && ($arg0 >> 10) < 0x1000000000000
printf " [possible infix header]"
end
end
# `caml_summary item` outputs a short text description of `item`, with
# no newline.
define caml_summary
if ($arg0 & 1) == 1
caml_int $arg0
end
if ($arg0 & 7) == 0
# aligned pointer
caml_search $arg0
printf " "
caml_header $arg0
end
if ($arg0 & 1) == 0 && ($arg0 & 7)
printf "UNALIGNED POINTER: %lx\n", $caml_last
end
end
# `caml_block item` describes `item`, which should be a pointer to a
# Caml block, over several lines.
define caml_block
printf "%#lx: ", $arg0 - $caml_word_size
set $caml_block_ptr = $arg0
caml_search $caml_block_ptr
printf " "
caml_header $caml_block_ptr
set $caml_block_size = $size
set $caml_block_tag = $tag
set $caml_next = $caml_block_ptr + $caml_word_size * ($caml_block_size + 1)
printf "\n"
if $caml_block_tag == 252
x/s $caml_block_ptr
end
if $caml_block_tag == 253
x/f $caml_block_ptr
end
if $caml_block_tag == 254
while $count < $caml_block_size && $count < 10
if $count + 1 < $caml_block_size
x/2f $caml_block_ptr + $caml_word_size * $count
else
x/f $caml_block_ptr + $caml_word_size * $count
end
set $count = $count + 2
end
if $count < $caml_block_size
printf "... truncated ...\n"
end
end
if $caml_block_tag == 249
printf "... infix header, displaying enclosing block:\n"
set $mybaseaddr = $caml_block_ptr - $caml_word_size * $caml_block_size
set $save_ptr = $caml_block_ptr
set $save_size = $caml_block_size
caml_block $mybaseaddr
# restore values clobbered by the recursive call (yuck)
set $caml_block_tag = 249
set $caml_block_ptr = $save_ptr
set $caml_block_size = $save_size
end
if $caml_block_tag != 249 && $caml_block_tag != 252 && \
$caml_block_tag != 253 && $caml_block_tag != 254
set $isvalues = $caml_block_tag < 251
set $count = 0
while $count < $caml_block_size && $count < 10
set $adr = $caml_block_ptr + $caml_word_size * $count
set $field = * (unsigned long *) $adr
printf "%#lx: [%d] 0x%016lx ", $adr, $count, $field
# If closure, zeroth field is a code address.
if $caml_block_tag == 247 && $count == 0
printf "code address? "
end
# Decode closure information field
if ($field & 1) == 1 && $caml_block_tag == 247 && $count == 1
printf "arity %d non-scannable %d", \
$field >> ($caml_word_bits - 8), \
($field & ((1ul << ($caml_word_bits-8))-1)) >> 1
else
caml_summary $field
end
printf "\n"
set $count = $count + 1
end
if $count < $caml_block_size
printf "... truncated ...\n"
end
end
printf "next block head: %#lx value: %#lx\n", \
$caml_block_ptr + $caml_word_size * $caml_block_size, \
$caml_block_ptr + $caml_word_size * ($caml_block_size+1)
end
# `caml item` describes the Caml value `item`, over several lines if
# appropriate. This function is the main point of this file.
define caml
set $caml_last = $arg0
set $caml_next = 0
if ($caml_last & 1) == 1
caml_int $caml_last
end
if ($caml_last & 7) == 0
caml_block $caml_last
end
printf "\n"
end
document caml
Output a description of a the Caml value VALUE, in a low-level but legible
format, including information about where on the heap it is located, and any
header and fields it contains.
end
# displays the next OCaml value in memory
define caml_next
if $caml_next
caml $caml_next
else
printf "No next block\n"
end
end
document caml_next
If the most recent value described was a heap block, "caml-next" describes
the following block on the heap.
end
# displays the n-th field of the previously displayed value
define caml_field
set $caml_field = ((long *) $caml_last)[$arg0]
caml $caml_field
end
document caml_field
If the most recent value described was a heap block, "caml-field N" describes
the Nth field in that block.
end