GDB - 별도창에 대상어플리케이션 출력 표시
저는 GDB를 사용하여 제 C 애플리케이션 중 일부를 디버깅하고 있습니다.현재 제가 하는 일은 대상 어플리케이션을 로드하고 30번 라인에서 중단점을 설정하여 실행하는 것입니다.
GDB 터미널 창을 통해 중단점 처리를 제어할 수 있는 상태에서 새로운 터미널 창에 자신의 어플리케이션의 출력을 표시하도록 하고 싶지만 적절한 스위치를 찾을 수 없었던 것 같습니다.GDB에서 제 프로그램의 출력을 자체 창에 표시할 수 있는 방법은 없습니까?
GDbtty 명령어 사용법에 대해 궁금해하는 사람들을 위해 여기 간단한 설명이 있습니다.
- 새 콘솔 창을 엽니다.GDB에서 실행 중인 프로그램의 출력을 여기로 리디렉션합니다.이것이 우리의 출력창입니다.
더 실행
tty
출력 창에 명령을 입력합니다.기본 콘솔에서 사용 중인 tty의 이름이 표시됩니다.$ tty
/dev/pts/4
다른 콘솔 창을 열고 여기서 GDB를 시작합니다.이것을 GDB 창이라고 부르도록 하겠습니다.
이제 위에서 얻은 tty 파일명을 사용하여 GDB에서 tty 명령을 실행한 후 디버깅 과정을 시작합니다.
(gdb) tty /dev/pts/4
(gdb) run
이제 출력창에서 프로그램 출력을 따로 볼 수 있을 것입니다.
: GDBset new-console on
명령어는 Linux에서 작동하지 않습니다!이것은 윈도우에서만 실행되도록 되어있습니다.리눅스에서 위에 설명한 tty 메서드를 사용합니다.
을 사용할 수 .set new-console on
이를 달성하기 위해 여기에 나와 있는 것입니다.
이를 위한 또 다른 방법은 (사용자가 사용할 수 있다고 가정할 때) gdb서버에서 대상 프로그램을 시작하는 것입니다.그러면 별도의 창에서 시작한 GDB를 gdb 서버에 연결할 수 있습니다.
창 A에서:
gdbserver :12345 myprog [args...]
창 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)
가장 , 은 의 을 로 가 로 을 가 tail -f
다른 터미널에 있는 파일입니다.리디렉션은 다음과 같이 수행됩니다.run > filename
, GDB 문서에 기록된 바와 같이.
GDB의tty
명령어는 작동하지만 bash를 디버깅하려는 경우처럼 대화형 프로그램에서는 잘 작동하지 않습니다.대화형이 아닌 프로그램의 경우에도 다음을 얻을 수 있습니다.
warning: GDB: Failed to set controlling terminal: Operation not permitted
이 두 가지 문제를 모두 해결하기 위해 작은 프로그램을 작성했습니다.
// 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;
}
프로그램을 다음에 저장한다고 가정합니다.idleterm.c
컴파일하기:
> gcc -o idleterm idleterm.c -luring
사용하려면 하나의 터미널 창을 시작하고, 그 창에서 실행합니다.idleterm
의 이름을 첨부할 tty의 이름을 인쇄합니다.
> ./idleterm
pid = 3405922 tty = /dev/pts/0
█
해당 tty 경로를 복사하여 두 번째 창에서 gdb 세션에 붙여넣습니다.
> gdb bash
Reading symbols from bash...
(No debugging symbols found in bash)
(gdb) tty /dev/pts/0
(gdb) r
Starting program: /usr/bin/bash
…
첫 번째 창에 bash 프롬프트가 나타납니다.특별한 TTY 동작이 필요한 bash와의 모든 상호 작용은 다음을 포함하여 정상적으로 작동합니다.^C
,^Z
,기타.
idleterm
는 ^C 및 ^Z를 포함한 모든 키보드 입력을 디버깅 중인 자식 프로세스로 전달합니다.따라서 유휴 기간을 멈추려면 별도의 창에서 이 기간을 죽여야 합니다.그래서.idleterm
pid를 찍어냅니다.pid를 복사한 다음 kill 명령에 붙여넣습니다.
> kill 3405922
단 한 가지의 예가 있다면idleterm
시스템 상에서 실행되는 것, 물론 당신은 단지 사용할 수 있습니다.killall
.
그냥 사용.tty
지휘.프로그램의 출력을 /dev/pts/5로 리디렉션하려면 다음 유형을 입력합니다.
tty /dev/pts/5
맥에서 lldb를 사용하면 디버거가 원래 창에서 제어하는 동안 새 터미널 창에서 프로그램을 실행합니다.
$ lldb <prog>
(lldb) b main # if you want to set a breakpoint
(lldb) process launch --tty -- <args>
지정된 tty(단말기 창)의 프로세스로 프로그램을 실행합니다.
$ 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>
언급URL : https://stackoverflow.com/questions/8963208/gdb-display-output-of-target-application-in-a-separate-window
'programing' 카테고리의 다른 글
호스트 ' xxx.xx.xxx .xxx'은(는) 이 MySQL 서버에 연결할 수 없습니다. (0) | 2023.09.13 |
---|---|
오류 유형:스트림이 필요한 곳에 잘못된 개체를 제공했습니다.관측 가능, 약속, 배열 또는 반복 가능한 값을 제공할 수 있습니다. (0) | 2023.09.13 |
Wordpress - 비밀번호 변경 시 사용자 알림 비활성화 (0) | 2023.09.13 |
파워쉘을 이용한 window용 git client 다운로드 및 설치 방법 (0) | 2023.09.13 |
PDO 거짓 양의 교착 상태 (0) | 2023.09.13 |