Files
clang-p2996/cross-project-tests/debuginfo-tests/dexter/dex/debugger/dbgeng/setup.py
Tobias Hieta f98ee40f4b [NFC][Py Reformat] Reformat python files in the rest of the dirs
This is an ongoing series of commits that are reformatting our
Python code. This catches the last of the python files to
reformat. Since they where so few I bunched them together.

Reformatting is done with `black`.

If you end up having problems merging this commit because you
have made changes to a python file, the best way to handle that
is to run git checkout --ours <yourfile> and then reformat it
with black.

If you run into any problems, post to discourse about it and
we will try to help.

RFC Thread below:

https://discourse.llvm.org/t/rfc-document-and-standardize-python-code-style

Reviewed By: jhenderson, #libc, Mordante, sivachandra

Differential Revision: https://reviews.llvm.org/D150784
2023-05-25 11:17:05 +02:00

158 lines
5.0 KiB
Python

# DExTer : Debugging Experience Tester
# ~~~~~~ ~ ~~ ~ ~~
#
# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
# See https://llvm.org/LICENSE.txt for license information.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
from ctypes import *
from . import client
from . import control
from . import symbols
from .probe_process import probe_state
from .utils import *
class STARTUPINFOA(Structure):
_fields_ = [
("cb", c_ulong),
("lpReserved", c_char_p),
("lpDesktop", c_char_p),
("lpTitle", c_char_p),
("dwX", c_ulong),
("dwY", c_ulong),
("dwXSize", c_ulong),
("dwYSize", c_ulong),
("dwXCountChars", c_ulong),
("dwYCountChars", c_ulong),
("dwFillAttribute", c_ulong),
("wShowWindow", c_ushort),
("cbReserved2", c_ushort),
("lpReserved2", c_char_p),
("hStdInput", c_void_p),
("hStdOutput", c_void_p),
("hStdError", c_void_p),
]
class PROCESS_INFORMATION(Structure):
_fields_ = [
("hProcess", c_void_p),
("hThread", c_void_p),
("dwProcessId", c_ulong),
("dwThreadId", c_ulong),
]
def fetch_local_function_syms(Symbols, prefix):
syms = Symbols.get_all_functions()
def is_sym_in_src_dir(sym):
name, data = sym
symdata = Symbols.GetLineByOffset(data.Offset)
if symdata is not None:
srcfile, line = symdata
if prefix in srcfile:
return True
return False
syms = [x for x in syms if is_sym_in_src_dir(x)]
return syms
def break_on_all_but_main(Control, Symbols, main_offset):
mainfile, _ = Symbols.GetLineByOffset(main_offset)
prefix = "\\".join(mainfile.split("\\")[:-1])
for name, rec in fetch_local_function_syms(Symbols, prefix):
if name == "main":
continue
bp = Control.AddBreakpoint2(offset=rec.Offset, enabled=True)
# All breakpoints are currently discarded: we just sys.exit for cleanup
return
def setup_everything(binfile):
from . import client
from . import symbols
Client = client.Client()
Client.Control.SetEngineOptions(0x20) # DEBUG_ENGOPT_INITIAL_BREAK
Client.CreateProcessAndAttach2(binfile)
# Load lines as well as general symbols
sym_opts = Client.Symbols.GetSymbolOptions()
sym_opts |= symbols.SymbolOptionFlags.SYMOPT_LOAD_LINES
Client.Symbols.SetSymbolOptions(sym_opts)
# Need to enter the debugger engine to let it attach properly.
res = Client.Control.WaitForEvent(timeout=1000)
if res == S_FALSE:
# The debugee apparently didn't do anything at all. Rather than risk
# hanging, bail out at this point.
client.TerminateProcesses()
raise Exception("Debuggee did not start in a timely manner")
# Enable line stepping.
Client.Control.Execute("l+t")
# Enable C++ expression interpretation.
Client.Control.SetExpressionSyntax(cpp=True)
# We've requested to break into the process at the earliest opportunity,
# and WaitForEvent'ing means we should have reached that break state.
# Now set a breakpoint on the main symbol, and "go" until we reach it.
module_name = Client.Symbols.get_exefile_module_name()
offset = Client.Symbols.GetOffsetByName("{}!main".format(module_name))
breakpoint = Client.Control.AddBreakpoint2(offset=offset, enabled=True)
Client.Control.SetExecutionStatus(control.DebugStatus.DEBUG_STATUS_GO)
# Problem: there is no guarantee that the client will ever reach main,
# something else exciting could happen in that time, the host system may
# be very loaded, and similar. Wait for some period, say, five seconds, and
# abort afterwards: this is a trade-off between spurious timeouts and
# completely hanging in the case of a environmental/programming error.
res = Client.Control.WaitForEvent(timeout=5000)
if res == S_FALSE:
client.TerminateProcesses()
raise Exception("Debuggee did not reach main function in a timely manner")
break_on_all_but_main(Client.Control, Client.Symbols, offset)
# Set the default action on all exceptions to be "quit and detach". If we
# don't, dbgeng will merrily spin at the exception site forever.
filts = Client.Control.GetNumberEventFilters()
for x in range(filts[0], filts[0] + filts[1]):
Client.Control.SetExceptionFilterSecondCommand(x, "qd")
return Client
def step_once(client):
client.Control.Execute("p")
try:
client.Control.WaitForEvent()
except Exception as e:
if (
client.Control.GetExecutionStatus()
== control.DebugStatus.DEBUG_STATUS_NO_DEBUGGEE
):
return None # Debuggee has gone away, likely due to an exception.
raise e
# Could assert here that we're in the "break" state
client.Control.GetExecutionStatus()
return probe_state(client)
def main_loop(client):
res = True
while res is not None:
res = step_once(client)
def cleanup(client):
client.TerminateProcesses()