Mirror of the gdb mailing list
 help / color / mirror / Atom feed
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()


  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