From: Xavier de Gaye <xdegaye@gmail.com>
To: Jan Kratochvil <jan.kratochvil@redhat.com>
Cc: Kevin Pouget <kevin.pouget@gmail.com>, gdb@sourceware.org
Subject: Re: GDB and LD_PRELOAD library-call interception
Date: Sun, 03 Apr 2011 16:54:00 -0000 [thread overview]
Message-ID: <BANLkTi=bWEmCGRhxgFZAccWyqRZtrU4MQA@mail.gmail.com> (raw)
In-Reply-To: <20110331121617.GA32739@host1.jankratochvil.net>
[-- Attachment #1: Type: text/plain, Size: 1465 bytes --]
On Thu, Mar 31, 2011 at 2:16 PM, Jan Kratochvil wrote:
>
> It is not such straightforward, GDB expects the PID it has spawned will be
> debugged while with xterm the process being debugged is its child.
>
> I guess you can write a small C helper which will:
> * create new pty
> * change its fds 0/1/2 to the slave of this pty
> * fork xterm -e own-helper-part pty-unique-id
> In own-helper-part interconnect the pty master part and its fds 0/1/2.
>
The attached files 'xterm_wrapper.py' and 'interconnect_pty.py' are a
raw implementation written in python of the above scheme. In gdb do:
set exec-wrapper python xterm_wrapper.py
The problem with the implementation is that the debuggee cannot set
the slave pty as its controlling terminal without forking (set
SET_CONTROLLING_TERMINAL to True in 'xterm_wrapper.py' in order to do
that, but then exec-wrapper cannot be used). So that it is not
possible to interrupt the debuggee with a 'C-c' character.
On the other hand the 'interconnect_pty.py' helper used by
'xterm_wrapper.py' can also be used by itself in stand-alone. When run
without arguments, it creates a pty and prints the slave pty name so
that it can be used in gdb with:
set inferior-tty /dev/pts/nn
It can also be made to spawn gdb in a new xterm and set correctly the
'-tty' gdb option with tne new pty name (kind of the reverse of the
initial scheme):
python interconnect_pty.py --exec gdb --args '/path/to/debuggee'
Xavier
[-- Attachment #2: interconnect_pty.py --]
[-- Type: text/x-python, Size: 3670 bytes --]
#! /usr/bin/env python
import os
import sys
import signal
import errno
import copy
import pty
import optparse
import termios
import asyncore
class FileDispatcher(asyncore.file_dispatcher):
def __init__(self, in_fd, out_fd, quit_char=None):
asyncore.file_dispatcher.__init__(self, in_fd)
self.out_fd = out_fd
self.quit_char = quit_char
def writable(self):
return False
def handle_read(self):
# called from the select loop whenever data is available
try:
data = self.recv(1024)
# terminate the select loop
if data == self.quit_char:
raise asyncore.ExitNow(
'\n%s terminated.' % os.path.basename(sys.argv[0]))
os.write(self.out_fd, data)
except OSError, err:
if err[0] != errno.EAGAIN:
raise asyncore.ExitNow(err)
def parse_options(argv):
formatter = optparse.IndentedHelpFormatter(max_help_position=30)
parser = optparse.OptionParser(
usage='usage: python %prog [options]',
formatter=formatter)
parser.add_option('-e', '--exec',
type='string', dest='pgm',
help='program to spawn in a new xterm terminal '
'that will use the slave pseudo terminal')
parser.add_option('-t', '--tty',
type='string', default='-tty', metavar='TTY_OPT',
help='pass to PGM the slave pseudo terminal name using'
' the TTY_OPT option (default \'%default\')')
parser.add_option('-a', '--args',
type='string',
help='PGM arguments (must be quoted)')
parser.add_option('-m', '--master_fd',
type='int', metavar='FD',
help='master pseudo terminal file descriptor to use')
(options, args) = parser.parse_args(args=argv)
return options
def spawn_xterm(options, ptyname, slave_fd, master_fd):
argv = ['xterm', '-e', options.pgm, options.tty, ptyname]
if options.args is not None:
# FIXME quotes in args are not handled
argv.extend(options.args.split())
pid = os.fork()
if pid == 0:
os.close(slave_fd)
os.close(master_fd)
os.setsid()
os.execvp(argv[0], argv)
master_fd = None
def sigint_handler(signum, frame):
# write a C-c character
if master_fd is not None:
os.write(master_fd, chr(3))
def main():
global master_fd
options = parse_options(sys.argv[1:])
master_fd = options.master_fd
if not isinstance(master_fd, int):
master_fd, slave_fd = pty.openpty()
ptyname = os.ttyname(slave_fd)
print "Slave pseudo terminal to use: '%s'" % ptyname
if options.pgm is not None:
spawn_xterm(options, ptyname, slave_fd, master_fd)
print 'Type C-a to exit.\n'
signal.signal(signal.SIGINT, sigint_handler)
# no echo, no canonical processing
attr = termios.tcgetattr(0)
init_attr = copy.deepcopy(attr)
attr[3] = attr[3] & ~termios.ECHO
attr[3] = attr[3] & ~termios.ICANON
termios.tcsetattr(0, termios.TCSADRAIN, attr)
# interconnect stdin to master_fd, and master_fd to stdout
# with an asyncore select loop
# C-a is the Quit character
master_slave = FileDispatcher(0, master_fd, chr(1))
slave_master = FileDispatcher(master_fd, 1)
err = ''
try:
while asyncore.socket_map:
asyncore.poll()
except asyncore.ExitNow, err:
pass
os.close(slave_fd)
os.close(master_fd)
termios.tcsetattr(0, termios.TCSADRAIN, init_attr)
if err:
print err
if __name__ == '__main__':
main()
[-- Attachment #3: xterm_wrapper.py --]
[-- Type: text/x-python, Size: 1072 bytes --]
#! /usr/bin/env python
import sys
import os
import pty
import termios
import fcntl
def fork_xterm(master_fd, slave_fd):
pid = os.fork()
if pid == 0:
os.close(slave_fd)
helper = os.path.join(
os.path.dirname(sys.argv[0]), 'interconnect_pty.py')
argv = ['xterm', '-e', 'python', helper, '--master_fd', str(master_fd)]
os.execvp(argv[0], argv)
os.close(master_fd)
return pid
def exec_pgm(slave_fd, argv):
os.dup2(slave_fd, 0)
os.dup2(slave_fd, 1)
os.dup2(slave_fd, 2)
os.close(slave_fd)
os.execvp(argv[0], argv)
SET_CONTROLLING_TERMINAL = False
def main():
master_fd, slave_fd = pty.openpty()
pid = fork_xterm(master_fd, slave_fd)
argv = sys.argv[1:]
if SET_CONTROLLING_TERMINAL:
argv[0] = os.path.abspath(argv[0])
pid = os.fork()
if pid == 0:
os.setsid()
fcntl.ioctl(slave_fd, termios.TIOCSCTTY)
exec_pgm(slave_fd, argv)
else:
exec_pgm(slave_fd, argv)
if __name__ == '__main__':
main()
next prev parent reply other threads:[~2011-04-03 16:54 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-03-31 8:25 Kevin Pouget
2011-03-31 8:47 ` Jan Kratochvil
2011-03-31 9:47 ` Kevin Pouget
2011-03-31 12:16 ` Jan Kratochvil
2011-03-31 15:07 ` Tom Tromey
2011-04-03 16:54 ` Xavier de Gaye [this message]
[not found] ` <BANLkTi=j6+-85R4B+N1Nd5kb9bkEZfsT9A@mail.gmail.com>
2011-04-04 13:35 ` Kevin Pouget
2011-03-31 15:06 ` Tom Tromey
2011-03-31 15:55 ` Kevin Pouget
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='BANLkTi=bWEmCGRhxgFZAccWyqRZtrU4MQA@mail.gmail.com' \
--to=xdegaye@gmail.com \
--cc=gdb@sourceware.org \
--cc=jan.kratochvil@redhat.com \
--cc=kevin.pouget@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox