Created
October 3, 2018 14:12
-
-
Save ArtemPisarenko/6d54d14db0509d02d60be3a3a750b559 to your computer and use it in GitHub Desktop.
GDB script to workaround issues with GDB debugging in Qt Creator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# | |
# GDB python script for silly QtCreator, when it used to run debug sessions | |
# with attaching to running process or remote gdb server. | |
# | |
# It automatically fixes following issues: | |
# - there are no way to allow automatic loading of .gdbinit/python scripts supplied with binary | |
# in a safe and/or convinient manner, i.e. without disabling safe-load option and/or | |
# playing with safe-load paths in ~/.gdbinit | |
# (you may see warning from gdb in debugger console) | |
# - execution automatically continued after connecting to remote gdb target, | |
# as a result you can't do some early preparations | |
# (e.g. insert breakpoints in everyting that runs before 'main') | |
# - other resctrictions because of cwd leaves default (user home) | |
# | |
# Using: | |
# Just add 'source /path/to/this_script' to "Additional Startup Commands" | |
# in "Options..."->"Debugger"->"GDB" tab. | |
# When attaching to process, if directory with binary contains file named '<binary_name>.debugpath', | |
# then its content being read as full path and if it's valid, then it set as current working directory. | |
# Setting cwd also implies loading scripts from it rather than from binary location, which adds support of '.gdbinit' also. | |
# | |
# Reqirements for attach to gdb target: | |
# 'readelf' must be installed | |
# | |
# TODO: respect auto-load parameter (it may be off) | |
import gdb | |
import os.path | |
import subprocess | |
log_prefix = __file__ + ": " | |
def add_program_to_autoloadsafepath(exec_binary_path): | |
gdb.execute("add-auto-load-safe-path " + os.path.dirname(exec_binary_path)) | |
def load_program_scripts(exec_binary_path): | |
global log_prefix | |
absdirpath = os.path.dirname(exec_binary_path) + "/" | |
reldirpath = absdirpath | |
if (os.path.isfile(exec_binary_path + ".debugpath")): | |
with open(exec_binary_path + ".debugpath", 'r') as f_debugpath: | |
debugpath = f_debugpath.read().replace('\n', '') | |
if (os.path.isdir(debugpath)): | |
gdb.write(log_prefix + " auto changing cwd to '" + debugpath + "'\n") | |
gdb.execute("cd " + debugpath) | |
absdirpath = debugpath + "/" | |
reldirpath = "" | |
if (os.path.isfile(absdirpath + ".gdbinit")): | |
gdb.write(log_prefix + " auto loading '.gdbinit'\n") | |
gdb.execute("source .gdbinit") | |
debug_bin_path = absdirpath + os.path.basename(exec_binary_path) | |
script_path = reldirpath + os.path.basename(exec_binary_path) | |
if (os.path.isfile(debug_bin_path + "-gdb.gdb")): | |
script_path += "-gdb.gdb" | |
elif (os.path.isfile(debug_bin_path + "-gdb.py")): | |
script_path += "-gdb.py" | |
elif (os.path.isfile(debug_bin_path + "-gdb.scm")): | |
script_path += "-gdb.scm" | |
else: | |
return | |
gdb.write(log_prefix + " auto loading '" + script_path + "'\n") | |
gdb.execute("source " + script_path) | |
def set_pause_on_entry(exec_binary_path): | |
entry_point_address = subprocess.check_output('readelf -h ' + exec_binary_path + ' | sed -n \'s/\ *Entry point.*\:\ *//p\' | tr -d \'\n\'', shell=True).decode() | |
gdb.Breakpoint("*"+entry_point_address, internal=True) | |
def event_handler_new_objfile(event): | |
global log_prefix | |
# Assuming this event fired only for executable binary, | |
# which expected to be loaded first. | |
# Disable event for other object files, which may potentially be loaded later | |
gdb.events.new_objfile.disconnect(event_handler_new_objfile) | |
exec_binary_path = event.new_objfile.filename | |
add_program_to_autoloadsafepath(exec_binary_path) | |
if (gdb.selected_inferior().was_attached): | |
# Attaching to running process: | |
# Here it's too late to fix-up auto-loading scripts, | |
# because by default cwd is user home. | |
# So let's just emulate necessary steps ourselves, but with differences | |
load_program_scripts(exec_binary_path) | |
else: | |
# Attaching to remote gdb target: | |
# Don't let program start execution | |
set_pause_on_entry(exec_binary_path) | |
gdb.write(log_prefix + " loaded\n") | |
gdb.events.new_objfile.connect(event_handler_new_objfile) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment