• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2014 the V8 project authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5# Print tagged object.
6define job
7call (void) _v8_internal_Print_Object((void*)($arg0))
8end
9document job
10Print a v8 JavaScript object
11Usage: job tagged_ptr
12end
13
14# Print content of v8::internal::Handle.
15define jh
16call (void) _v8_internal_Print_Object(*((v8::internal::Object**)($arg0).location_))
17end
18document jh
19Print content of a v8::internal::Handle
20Usage: jh internal_handle
21end
22
23# Print content of v8::Local handle.
24define jlh
25call (void) _v8_internal_Print_Object(*((v8::internal::Object**)($arg0).val_))
26end
27document jlh
28Print content of a v8::Local handle
29Usage: jlh local_handle
30end
31
32# Print Code objects containing given PC.
33define jco
34  if $argc == 0
35    call (void) _v8_internal_Print_Code((void*)($pc))
36  else
37    call (void) _v8_internal_Print_Code((void*)($arg0))
38  end
39end
40document jco
41Print a v8 Code object from an internal code address
42Usage: jco pc
43end
44
45# Print TransitionTree.
46define jtt
47call (void) _v8_internal_Print_TransitionTree((void*)($arg0))
48end
49document jtt
50Print the complete transition tree of the given v8 Map.
51Usage: jtt tagged_ptr
52end
53
54# Print JavaScript stack trace.
55define jst
56call (void) _v8_internal_Print_StackTrace()
57end
58document jst
59Print the current JavaScript stack trace
60Usage: jst
61end
62
63# Print TurboFan graph node.
64define pn
65call _v8_internal_Node_Print((void*)($arg0))
66end
67document pn
68Print a v8 TurboFan graph node
69Usage: pn node_address
70end
71
72# Skip the JavaScript stack.
73define jss
74set $js_entry_sp=v8::internal::Isolate::Current()->thread_local_top()->js_entry_sp_
75set $rbp=*(void**)$js_entry_sp
76set $rsp=$js_entry_sp + 2*sizeof(void*)
77set $pc=*(void**)($js_entry_sp+sizeof(void*))
78end
79document jss
80Skip the jitted stack on x64 to where we entered JS last.
81Usage: jss
82end
83
84# Execute a simulator command.
85python
86import gdb
87
88class SimCommand(gdb.Command):
89  """Sim the current program."""
90
91  def __init__ (self):
92    super (SimCommand, self).__init__ ("sim", gdb.COMMAND_SUPPORT)
93
94  def invoke (self, arg, from_tty):
95    arg_c_string = gdb.Value(arg)
96    cmd_func = gdb.selected_frame().read_var("_v8_internal_Simulator_ExecDebugCommand")
97    cmd_func(arg_c_string)
98
99SimCommand()
100end
101
102# Print stack trace with assertion scopes.
103define bta
104python
105import re
106frame_re = re.compile("^#(\d+)\s*(?:0x[a-f\d]+ in )?(.+) \(.+ at (.+)")
107assert_re = re.compile("^\s*(\S+) = .+<v8::internal::Per\w+AssertScope<v8::internal::(\S*), (false|true)>")
108btl = gdb.execute("backtrace full", to_string = True).splitlines()
109for l in btl:
110  match = frame_re.match(l)
111  if match:
112    print("[%-2s] %-60s %-40s" % (match.group(1), match.group(2), match.group(3)))
113  match = assert_re.match(l)
114  if match:
115    if match.group(3) == "false":
116      prefix = "Disallow"
117      color = "\033[91m"
118    else:
119      prefix = "Allow"
120      color = "\033[92m"
121    print("%s -> %s %s (%s)\033[0m" % (color, prefix, match.group(2), match.group(1)))
122end
123end
124document bta
125Print stack trace with assertion scopes
126Usage: bta
127end
128
129# Search for a pointer inside all valid pages.
130define space_find
131  set $space = $arg0
132  set $current_page = $space->first_page()
133  while ($current_page != 0)
134    printf "#   Searching in %p - %p\n", $current_page->area_start(), $current_page->area_end()-1
135    find $current_page->area_start(), $current_page->area_end()-1, $arg1
136    set $current_page = $current_page->next_page()
137  end
138end
139
140define heap_find
141  set $heap = v8::internal::Isolate::Current()->heap()
142  printf "# Searching for %p in old_space  ===============================\n", $arg0
143  space_find $heap->old_space() ($arg0)
144  printf "# Searching for %p in map_space  ===============================\n", $arg0
145  space_find $heap->map_space() $arg0
146  printf "# Searching for %p in code_space ===============================\n", $arg0
147  space_find $heap->code_space() $arg0
148end
149document heap_find
150Find the location of a given address in V8 pages.
151Usage: heap_find address
152end
153
154# The 'disassembly-flavor' command is only available on i386 and x84_64.
155python
156try:
157  gdb.execute("set disassembly-flavor intel")
158except gdb.error:
159  pass
160end
161set disable-randomization off
162
163# Install a handler whenever the debugger stops due to a signal. It walks up the
164# stack looking for V8_Dcheck / V8_Fatal / OS::DebugBreak frame and moves the
165# frame to the one above it so it's immediately at the line of code that
166# triggered the stop condition.
167python
168def v8_stop_handler(event):
169  frame = gdb.selected_frame()
170  select_frame = None
171  message = None
172  count = 0
173  # Limit stack scanning since the frames we look for are near the top anyway,
174  # and otherwise stack overflows can be very slow.
175  while frame is not None and count < 7:
176    count += 1
177    # If we are in a frame created by gdb (e.g. for `(gdb) call foo()`), gdb
178    # emits a dummy frame between its stack and the program's stack. Abort the
179    # walk if we see this frame.
180    if frame.type() == gdb.DUMMY_FRAME: break
181
182    if frame.name() == 'V8_Dcheck':
183      frame_message = gdb.lookup_symbol('message', frame.block())[0]
184      if frame_message:
185        message = frame_message.value(frame).string()
186      select_frame = frame.older()
187      break
188    if frame.name() is not None and frame.name().startswith('V8_Fatal'):
189      select_frame = frame.older()
190    if frame.name() == 'v8::base::OS::DebugBreak':
191      select_frame = frame.older()
192    frame = frame.older()
193
194  if select_frame is not None:
195    select_frame.select()
196    gdb.execute('frame')
197    if message:
198      print('DCHECK error: {}'.format(message))
199
200gdb.events.stop.connect(v8_stop_handler)
201end
202
203# Code imported from chromium/src/tools/gdb/gdbinit
204python
205
206import os
207import subprocess
208import sys
209
210compile_dirs = set()
211
212
213def get_current_debug_file_directories():
214  dir = gdb.execute("show debug-file-directory", to_string=True)
215  dir = dir[
216      len('The directory where separate debug symbols are searched for is "'
217         ):-len('".') - 1]
218  return set(dir.split(":"))
219
220
221def add_debug_file_directory(dir):
222  # gdb has no function to add debug-file-directory, simulates that by using
223  # `show debug-file-directory` and `set debug-file-directory <directories>`.
224  current_dirs = get_current_debug_file_directories()
225  current_dirs.add(dir)
226  gdb.execute(
227      "set debug-file-directory %s" % ":".join(current_dirs), to_string=True)
228
229
230def newobj_handler(event):
231  global compile_dirs
232  compile_dir = os.path.dirname(event.new_objfile.filename)
233  if not compile_dir:
234    return
235  if compile_dir in compile_dirs:
236    return
237  compile_dirs.add(compile_dir)
238
239  # Add source path
240  gdb.execute("dir %s" % compile_dir)
241
242  # Need to tell the location of .dwo files.
243  # https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html
244  # https://crbug.com/603286#c35
245  add_debug_file_directory(compile_dir)
246
247# Event hook for newly loaded objfiles.
248# https://sourceware.org/gdb/onlinedocs/gdb/Events-In-Python.html
249gdb.events.new_objfile.connect(newobj_handler)
250
251gdb.execute("set environment V8_GDBINIT_SOURCED=1")
252
253end
254