GDB – Ausgabe der Zielanwendung in einem separaten Fenster anzeigen

Lesezeit: 9 Minuten

Benutzer-Avatar
Beta

Ich verwende GDB, um einige meiner C-Anwendungen zu debuggen. Was ich derzeit tue, ist die Zielanwendung zu laden, einen Haltepunkt in Zeile 30 zu setzen und sie auszuführen.

Ich möchte, dass GDB die Ausgabe meiner eigenen Anwendung in einem neuen Terminalfenster anzeigt, während ich die Haltepunktbehandlung immer noch über das GDB-Terminalfenster steuern kann, aber ich konnte anscheinend keinen richtigen Schalter finden. Gibt es eine Möglichkeit, GDB dazu zu bringen, die Ausgabe meines Programms in einem eigenen Fenster anzuzeigen?

Benutzer-Avatar
Sandeep Datta

Für Leute, die sich fragen, wie man den GDB-Befehl tty benutzt, ist hier eine kurze Beschreibung …

  • Öffnen Sie ein neues Konsolenfenster. Wir werden die Ausgabe des unter GDB laufenden Programms hier umleiten. Dies ist unser Ausgabefenster.
  • Führen Sie die aus tty Befehl im Ausgabefenster. Dies zeigt den Namen des tty an, der von der zugrunde liegenden Konsole verwendet wird.

    $ tty
    /dev/pts/4

  • Öffnen Sie ein weiteres Konsolenfenster und starten Sie GDB hier. Nennen wir dies das GDB-Fenster.

  • Führen Sie nun den tty-Befehl in GDB mit dem oben erhaltenen tty-Dateinamen aus und starten Sie dann den Debugging-Prozess.

    (gdb) tty /dev/pts/4
    (gdb) run

Jetzt sollten Sie die Programmausgabe separat im Ausgabefenster sehen können.

Hinweis: Die GDB set new-console on Befehl funktioniert nicht unter Linux! Es soll nur unter Windows ausgeführt werden. Verwenden Sie die oben beschriebene tty-Methode unter Linux.

  • Dies war der beste Weg, um unter Linux eine separate Terminalausgabe zu erhalten.

    – NoodleCollie

    9. September 2018 um 12:38 Uhr

  • Ich habe es versucht und bekomme printf() ausgegeben, aber ich bekomme die ursprüngliche Nachricht warning: GDB: Failed to set controlling terminal: Operation not permitted. Ich habe gegoogelt, es sieht aus wie eine harmlose Warnmeldung, habe mich aber gefragt, ob es dafür eine Lösung gibt. Ich renne Ubuntu 20.04 auf VirtualBox.

    – Minh Tran

    24. Juni 2020 um 23:09 Uhr


  • Das würde wahrscheinlich für nicht-interaktive Programme reichen, aber für interaktive brauchen Sie wahrscheinlich eine gdbserver

    – x-yuri

    31. August 2020 um 11:06 Uhr

  • @MinhTran: Ich habe einen Weg gefunden, diese Fehlermeldung zu beheben. @x-yuri: GDBs tty tut funktionieren für interaktive Befehle, aber das von Ihnen angegebene tty darf keine untergeordneten Prozesse haben, die bereits mit ihm verbunden sind. Sie beide, siehe stackoverflow.com/a/71314902/1840698 .

    – rätselhafter Physiker

    1. März um 21:41 Uhr

Sie können verwenden set new-console on um dies wie gezeigt zu erreichen hier.

  • Oh, vielen Dank, das ist genau das, wonach ich gesucht habe. Ich werde Ihre Antwort auf jeden Fall im Hinterkopf behalten, wenn ich wieder mit GDB arbeite!

    – Beta

    9. März 2013 um 22:58 Uhr

  • Diese Antwort hat mir gerade das Leben gerettet. Ich weiß nicht, warum ich diese Einstellung vorher nicht finden konnte. Vielen Dank

    – Rick

    24. März 2014 um 6:29 Uhr

  • @Herr_Doktor Ich bin froh, dass es geholfen hat 🙂 Die Dokumentation im GNU-Stil neigt nicht dazu, sich leicht zu finden, sodass es verständlich ist, wie Sie sie möglicherweise verpasst haben.

    – Großwolf

    24. März 2014 um 11:17 Uhr

  • Scheint bei mir nicht zu funktionieren: Kein Symbol “neu” im aktuellen Kontext.

    – Sandeep Datta

    31. Juli 2015 um 15:44 Uhr

Benutzer-Avatar
Digitales Trauma

Eine andere Möglichkeit wäre, Ihr Zielprogramm mit gdbserver zu starten (vorausgesetzt, es steht Ihnen zur Verfügung). Dann können Sie GDB, das in einem separaten Fenster gestartet wurde, mit gdbserver verbinden.

GNU gdbserver-Dokumentation

Aus Fenster A:

gdbserver :12345 myprog [args...]

Aus Fenster B:

gdb myprog
GNU gdb 6.6
...
(gdb) target remote localhost:12345
Remote debugging using localhost:12345
0x009867c0 in ?? ()
(gdb) b main
Breakpoint 1 at 0x804834a: file myprog.c, line 40.
(gdb) c
Continuing.

Breakpoint 1, main (argc=1, argv=0xffff8904) at myprog.c:40
40          int i = 1;
(gdb) 

  • Sieht auch nach einer großartigen Lösung aus, vielen Dank für das Posten. Ich habe eigentlich noch nie mit gdbserver gearbeitet.

    – Beta

    9. März 2013 um 23:00 Uhr

  • Vielleicht möchten Sie stattdessen an “127.0.0.1:12345” binden.

    – ysdx

    3. Mai 2015 um 20:32 Uhr

Benutzer-Avatar
drrlvn

Der beste Weg, den ich kenne, ist, die Ausgabe des Programms in eine Datei umzuleiten und dann tail -f diese Datei in einem anderen Terminal. Umleitung ist erledigt run > filenamewie dokumentiert in der GDB-Dokumentation.

Benutz einfach tty Befehl. Wenn Sie möchten, dass die Ausgabe Ihres Programms nach /dev/pts/5 umgeleitet wird, geben Sie Folgendes ein:

tty /dev/pts/5

  • Ist das eine neue Option für den ‘tty’-Befehl? Auf meinem Fedora 19-System akzeptiert der Befehl ‚tty‘ diesen Parameter nicht.

    – KyleL

    13. Januar 2014 um 23:58 Uhr

  • @KdawgUD: Bist du sicher? Bei mir funktioniert der Befehl. Kannst du Fehlermeldung zeigen?

    – A. Michailow

    14. Januar 2014 um 7:19 Uhr

  • In Dokumenten hier Es gibt ein Beispiel.

    – A. Michailow

    14. Januar 2014 um 7:28 Uhr

  • Hier ist der Fehler: “tty: extra operand ‘/dev/pts/4′” unter Verwendung von Fedora 19

    – KyleL

    14. Januar 2014 um 17:46 Uhr


  • @KdawgUD: es gibt tty Dienstprogramm, das den Dateinamen des Terminals ausgibt, Sie können es in der Standard-Shell-Eingabeaufforderung verwenden und es akzeptiert keine Argumente. Um die Programmausgabe in GDB umzuleiten, sollten Sie sie in die GDB-CLI-Eingabeaufforderung eingeben.

    – A. Michailow

    18. Januar 2014 um 17:07 Uhr

GDBs tty Der Befehl funktioniert, aber er funktioniert nicht gut mit interaktiven Programmen, z. B. wenn Sie Bash debuggen möchten. Auch für nicht interaktive Programme erhalten Sie Folgendes:

warning: GDB: Failed to set controlling terminal: Operation not permitted

Ich habe ein kleines Programm geschrieben, um diese beiden Probleme zu beheben:

// Open a pty and let it idle, so that a process spawned in a different window
// can attach to it, start a new session, and set it as the controlling
// terminal. Useful for gdb debugging with gdb's `tty` command.
 
#include <inttypes.h>
typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64;
typedef  int8_t i8; typedef  int16_t i16; typedef  int32_t i32; typedef  int64_t i64;
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>

#include <termios.h>
#include <pty.h>
#include <liburing.h>

#define BSIZE 4096

void raw_terminal(void)
{
    if (!isatty(0))
        return;
    struct termios t;
    tcgetattr(0, &t);
    t.c_lflag &= ~(ISIG | ICANON | ECHO);
    tcsetattr(0, TCSANOW, &t);
}

// Refers to the state of a Joint /while it's waiting in io_uring_enter/.
enum State {
    READ,
    WRITE
};
// Joins two fds together, like splice, but not a syscall and works on any two
// fds.
struct Joint {
    u8 buf[BSIZE];
    i32 ifd;
    i32 ofd;
    enum State state;
    u32 nread;
};
void roll_joint(struct Joint *j, struct io_uring *ur, i32 ifd, i32 ofd)
{
    j->ifd = ifd;
    j->ofd = ofd;
    j->state = READ;
    struct io_uring_sqe *sqe = io_uring_get_sqe(ur);
    io_uring_prep_read(sqe, j->ifd, j->buf, BSIZE, 0);
    io_uring_sqe_set_data(sqe, j);
    io_uring_submit(ur);
}
i32 main(i32 argc, char **argv)
{
    raw_terminal();
    struct io_uring ur;
    assert(io_uring_queue_init(256, &ur, 0) == 0);

    i32 ptm, pts;
    assert(openpty(&ptm, &pts, NULL, NULL, NULL) == 0);
    dprintf(2, "pid = %u   tty = %s\n", getpid(), ttyname(pts));

    struct Joint jkbd;
    roll_joint(&jkbd, &ur, 0, ptm);
    struct Joint jscreen;
    roll_joint(&jscreen, &ur, ptm, 1);

    for (;;) {
        struct io_uring_cqe *cqe;
        for (;;) {
            // Actions like suspend to RAM can interrupt the io_uring_enter
            // syscall. If we get interrupted, try again. For all other errors,
            // bail. Also, wait_cqe negates the error for no reason. It never
            // returns positive numbers. Very silly.
            u32 res = -io_uring_wait_cqe(&ur, &cqe);
            if (res == 0)
                break;
            else if (res != EINTR) {
                dprintf(2, "io_uring_enter returns errno %d\n", res);
                exit(res);
            }
        }
        struct Joint *j = io_uring_cqe_get_data(cqe);
        if (j->state == READ) {
            // Exiting READ state. Finish with the read...
            j->nread = cqe->res;
            assert(j->nread > 0);

            // Now, start the write.
            j->state = WRITE;
            struct io_uring_sqe *sqe = io_uring_get_sqe(&ur);
            io_uring_prep_write(sqe, j->ofd, j->buf, j->nread, 0);
            io_uring_sqe_set_data(sqe, j);
            io_uring_submit(&ur);
        }
        else if (j->state == WRITE) {
            // Exiting WRITE state. Finish with the write...
            i64 nwritten = cqe->res;
            assert(nwritten == j->nread);

            // Now, start the read.
            j->state = READ;
            struct io_uring_sqe *sqe = io_uring_get_sqe(&ur);
            io_uring_prep_read(sqe, j->ifd, j->buf, BSIZE, 0);
            io_uring_sqe_set_data(sqe, j);
            io_uring_submit(&ur);
        }
        io_uring_cqe_seen(&ur, cqe);
    }

    io_uring_queue_exit(&ur);
    return 0;
}

Angenommen, Sie speichern das Programm unter idleterm.c. Um es zu kompilieren:

> gcc -o idleterm idleterm.c -luring

Um es zu verwenden, starten Sie ein Terminalfenster und führen Sie es in diesem Fenster aus idleterm. Es wird der Name des tty gedruckt, an das angehängt werden soll:

> ./idleterm
pid = 3405922   tty = /dev/pts/0
█

Kopieren Sie diesen tty-Pfad und fügen Sie ihn in einem zweiten Fenster in eine gdb-Sitzung ein:

> gdb bash
Reading symbols from bash...
(No debugging symbols found in bash)
(gdb) tty /dev/pts/0
(gdb) r
Starting program: /usr/bin/bash
…

Im ersten Fenster erscheint eine Bash-Eingabeaufforderung. Alle Interaktionen mit bash, die ein spezielles TTY-Verhalten erfordern, funktionieren normal, einschließlich ^C, ^Zetc.

idleterm geht vorbei alle Tastatureingabe bis zum zu debuggenden untergeordneten Prozess, einschließlich ^C und ^Z. Um also Idleterm zu stoppen, müssen Sie es von einem separaten Fenster aus beenden. Deshalb idleterm gibt seine pid aus. Kopieren Sie die PID und fügen Sie sie dann in den Kill-Befehl ein:

> kill 3405922

Wenn es nur eine Instanz von gibt idleterm auf dem System läuft, kann man natürlich einfach verwenden killall.

  • Ist das eine neue Option für den ‘tty’-Befehl? Auf meinem Fedora 19-System akzeptiert der Befehl ‚tty‘ diesen Parameter nicht.

    – KyleL

    13. Januar 2014 um 23:58 Uhr

  • @KdawgUD: Bist du sicher? Bei mir funktioniert der Befehl. Kannst du Fehlermeldung zeigen?

    – A. Michailow

    14. Januar 2014 um 7:19 Uhr

  • In Dokumenten hier Es gibt ein Beispiel.

    – A. Michailow

    14. Januar 2014 um 7:28 Uhr

  • Hier ist der Fehler: “tty: extra operand ‘/dev/pts/4′” unter Verwendung von Fedora 19

    – KyleL

    14. Januar 2014 um 17:46 Uhr


  • @KdawgUD: es gibt tty Dienstprogramm, das den Dateinamen des Terminals ausgibt, Sie können es in der Standard-Shell-Eingabeaufforderung verwenden und es akzeptiert keine Argumente. Um die Programmausgabe in GDB umzuleiten, sollten Sie sie in die GDB-CLI-Eingabeaufforderung eingeben.

    – A. Michailow

    18. Januar 2014 um 17:07 Uhr

Benutzer-Avatar
klares Licht

Mit lldb auf dem Mac führt Folgendes das Programm in einem neuen Terminalfenster aus, während der Debugger vom ursprünglichen Fenster aus steuert:

$ lldb   <prog>
(lldb) b main   # if you want to set a breakpoint
(lldb) process launch --tty -- <args>

Dadurch wird das Programm als Prozess in ausgeführt spezifizierten tty (Terminalfenster):

$ tty   # (in other window, get tty name)
/dev/ttys002

$ lldb  
(lldb) b main   # if you want to set a breakpoint
(lldb) process launch --tty=/dev/ttys002 -- <args>

1369820cookie-checkGDB – Ausgabe der Zielanwendung in einem separaten Fenster anzeigen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy