为什么 gdb mi 将 &"\n" 作为 return 提供给我的 -gdb-exit 命令?

Why does gdb mi give me &"\n" as return to my -gdb-exit command?

我正在编写一些必须与 gdb mi 通信的代码。所以我分叉了我的程序,放置了两个管道并在 child 中启动了 gdb mi,这样我就可以从 parent 中与 gdb mi 进行通信。 gdb 总是 returns "(gdb) \n" 当它完成时,所以我寻找它并编写我的下一个命令。这是我的代码的最小示例:

int main(){
    printf("Starting Test\n");

    int fromGDB[2], toGDB[2], nbytes;
    pid_t childpid;
    char readbuffer[80] = "";

    pipe(fromGDB);
    pipe(toGDB);

    if((childpid = fork())==-1)
    {
        perror("fork");
        exit(1);
    }

    if(childpid == 0){
        
        close(toGDB[1]);
        close(fromGDB[0]);
        
        int backup = dup(1);    //store stdout
        if (dup2(fromGDB[1],1) < 0){puts("hat nicht geklappt");}
        
        int backupStdin = dup(0); //store stdin
        if (dup2(toGDB[0],0) < 0){puts("hat nicht geklappt");}

        system("gdb -q --interpreter=mi2"); // start gdb mi

        dup2(backup,1); // restore stdout
        
        puts("child fertig");
        exit(0);
        
    }else{
        close(toGDB[0]);
        close(fromGDB[1]);

        char* writeCommand = "";
        int commandCounter = 0;

        while (commandCounter <3){
            nbytes = read(fromGDB[0],readbuffer,sizeof(readbuffer));
            printf("parent recived: %s", readbuffer);
            if (strncmp(readbuffer+strlen(readbuffer)-strlen("(gdb) \n"),"(gdb) \n", strlen("(gdb) \n")) == 0){
                switch (commandCounter){
                    case 0: writeCommand = "-file-exec-and-symbols /home/dev/spielwiese/build/main\n"; break;
                    case 1: writeCommand = "-gdb-exit\n"; break;
                    default: writeCommand = "you should never reach here\n"; break;
                }
                write(toGDB[1],writeCommand,strlen(writeCommand)+1);
                printf("wrote: %s", writeCommand);
                commandCounter++;
            }else if(strncmp(readbuffer,"^exit", sizeof("^exit")-1) == 0){
                break;
            }
            memset(readbuffer,'[=12=]',strlen(readbuffer)); //clear the readbuffer
        }

        puts("parent fertig");
        sleep(5);
    }
    
    return 0;
}

如果我手动调用相同的命令,这就是我得到的输出(-> 表示我的输入)

-> gdb -q --interpreter=mi2
=thread-group-added,id="i1"
(gdb) 
-> -file-exec-and-symbols /home/dev/spielwiese/build/main
^done
(gdb) 
-> -gdb-exit
^exit

但是如果我 运行 我的代码(本质上应该是一样的),我会得到这个输出:

Starting Test
parent recived: =thread-group-added,id="i1"
parent recived: (gdb) 
wrote: -file-exec-and-symbols /home/dev/spielwiese/build/main
parent recived: ^done
(gdb) 
wrote: -gdb-exit
parent recived: &"\n"
parent recived: ^done
(gdb) 
wrote: you should never reach here
parent fertig

根据 gdb mi 手册,& 在日志条目之前,但是这个日志条目是空的,换行符除外。另外,我不知道为什么应该有一个退出日志条目,或者为什么它无法退出,但不会产生错误。 此外,如果您知道 gdb mi 的任何更好的来源:https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html#GDB_002fMI,请告诉我。

您的示例代码存在多个问题,其中许多已在评论中进行了总结:

  • read()write() 仅传输指定的字节,或这些字节的前导子序列。他们不会将空字节附加到传输中。
  • read()write() 不能保证在任何给定调用上传输请求的全部字节数。
  • 您的缓冲区可能不够长,无法在一个 read().
  • 中容纳来自 child 的一些回复

According to the gdb mi manual, an & preceeds a log entry, but this log entry is empty, exept for the newline. Also, I don't know why there should be a log entry for exiting, or why it fails to exit, but doesen't produce an error.

上面的

None 解释了日志条目或其他行为差异,但这可能是:

                write(toGDB[1],writeCommand,strlen(writeCommand)+1);

假设传输了请求的全部字节数,您不仅要编写命令,还要编写字符串终止符。终止符不是 MI 协议的一部分,因此您的程序的行为与交互式会话不同。此外,特定的错误——一个额外的空字节——是一个特别有可能产生神秘输出的错误。我只能推测具体细节,但我可以相信 gdb 正在处理换行符后的额外空字节,就好像它终止了 zero-byte 命令一样。如果是这样,那么您实际上是在向 gdb 发出三个命令,而不是两个,并且 gdb 日志输出是关于空字节/空命令的。

您可能会发现流 I/O 比原始 I/O 对于您的目的更方便。这将使您免受 raw I/O 的许多特性的影响,并且会使 fgets() 可供您输入,这对您有利。 fdopen() 函数可以将流环绕在您的文件描述符周围:

    #define BUFFER_SIZE 1024

    // Parent
    FILE *fFromGDB = fdopen(fromGDB[0], "r");
    FILE *fToGDB = fdopen(fToGDB[1], "w");

    if (!fFromGDB || ! fToGDB) // ...

    // You probably want fToGDB to be line-buffered, not block buffered:
    setvbuf(fToGDB, NULL, _IOLBF, BUFFER_SIZE);

然后使用fputs()fgets()fprintf()。与 child.

互动

Also, if you know any better sources for gdb mi than this: https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html#GDB_002fMI , please let me know.

外部资源请求在off-topic这里。

无论如何,您参考的是相应的手册,而没有分析源代码,这是有关该问题的最终知识来源。