Trouble Using GDB to Debug amd64 Binaries in Docker on MacBook M1

Background

I’m running an x86/amd64 Debian 11 environment inside Docker on my MacBook Air with an M1 chip (Apple Silicon). I want to use gdb to debug programs compiled for amd64, but I’ve encountered issues.

After some research, I found several resources discussing how to debug x86 programs on macOS with Docker and Rosetta:

I’m currently using the method described in those posts. For example, to debug a program called bbsort, I do:

  1. Run the program with Rosetta debugserver:
ROSETTA_DEBUGSERVER_PORT=1234 ./bbsort &
  1. Launch gdb:
gdb ./bbsort
  1. Connect to the Rosetta debugserver:
target remote localhost:1234
  1. Set a breakpoint:
b 14
  1. Continue execution:
continue

The Problem

This approach works for attaching to already-running processes, but I can’t provide input via file redirection (e.g., < input.txt) in gdb.

For example, I have this simple test program:

// test_input.c
#include <stdio.h>
#include <string.h>

int main() {
    char buffer[256];

    printf("Program started. Waiting for input...\n");
    fflush(stdout); // Ensure message is printed immediately

    if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
        // Remove trailing newline
        buffer[strcspn(buffer, "\n")] = 0;
        printf("Program received: \"%s\"\n", buffer);
    } else {
        printf("Program received no input or an error occurred.\n");
    }

    fflush(stdout);
    printf("Program finished.\n");
    fflush(stdout);
    return 0;
}

After compiling it into an amd64 binary named test_input_x86_64, I want to debug it with input redirected from a file:

// my_test_input.txt
Hello from GDB test!

What I want to do is:

gdb ./test_input_x86_64 < my_test_input.txt

But this doesn’t work as expected. When I try to debug with gdb, the program appears to start, but it doesn’t seem to receive any input from my_test_input.txt.

Here is part of the output:

2023211759 Lab2/# ROSETTA_DEBUGSERVER_PORT=1234 ./test_input_x86_64 &
[2] 179
2023211759 Lab2/# gdb ./test_input_x86_64 < my_test_input.txt        
GNU gdb (Debian 10.1-1.7) 10.1.90.20210103-git
Copyright (C) 2021 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./test_input_x86_64...
gdb_59$ Undefined command: "Hello".  Try "help".
gdb_59$ Undefined command: "Hello".  Try "help".
gdb_59$ quit
2023211759 Lab2/# 

Goal

How can I debug an amd64 binary running under Rosetta on a Mac M1 via Docker, and also provide input to it from a file (like gdb ./program < input.txt), while still being able to set breakpoints and step through the program?

Any help would be greatly appreciated!

It looks like you’re trying to run an amd64 binary in a Docker container on Apple Silicon (M1/M2) via Rosetta and debug it using GDB, while also providing input to the program via file redirection (like gdb ./program < input.txt). The issue you’re encountering is that when redirecting input to GDB with <, it doesn’t seem to properly pass the input to the program, causing GDB to misinterpret it as commands.

The root of this issue is that GDB expects to interact with the program directly via standard input/output, but when you redirect input using <, the input stream is passed to GDB rather than to the target program running inside the Docker container under Rosetta.

Steps to achieve what you want:

To solve this, you can try a different approach that doesn’t rely on input redirection but still allows you to provide input to the program while debugging with GDB. Specifically, you can:

  1. Run the program normally under Rosetta with the debugserver.
  2. Use GDB to connect to the running process (as you’re doing).
  3. Manually provide input inside GDB using GDB’s call or set commands.

Here’s how you can do this:

1. Run the Program with Rosetta Debugserver

Start your program with the Rosetta debugserver, as you were doing:

ROSETTA_DEBUGSERVER_PORT=1234 ./test_input_x86_64 &

This will run your program in the background, ready for debugging.

2. Connect to the Program with GDB

Launch gdb with the program to start debugging:

gdb ./test_input_x86_64

Now connect GDB to the running process:

target remote localhost:1234

3. Provide Input Using GDB

Instead of using < to redirect input, you can simulate the input inside GDB itself. The fgets function in your program reads from stdin, so you can set the input manually in GDB using the call command.

For example, let’s say you want to provide the input "Hello from GDB test!" to the fgets function. You can use the following approach:

  • First, pause the program (if it’s already running) and set a breakpoint at the location where fgets is called (e.g., line 12):
b 12  # Assuming fgets is at line 12 in your source code
  • Then, run the program (or continue it) until it hits the breakpoint:
run

Once it breaks at line 12, you can simulate the input by setting the stdin stream. However, GDB doesn’t directly allow you to simulate stdin in the same way, but you can manually call the function to simulate input if needed.

Alternatively, you can redirect the input file inside the Docker container and have the program use it normally:

gdb ./test_input_x86_64
(gdb) target remote localhost:1234
(gdb) run < my_test_input.txt

This should allow GDB to provide the input from the file to the program.

4. Use continue and step to Debug Normally

After the input is provided, you can continue the program execution using the continue command, or step through the program with next or step.

(gdb) continue

Key Points to Note:

  • Input Redirection in GDB: GDB does not handle input redirection in the same way that a shell does, so < input.txt does not behave as expected inside GDB. You need to provide the input either manually or in a way that GDB can control.
  • Program Control: You can still control the execution of the program, set breakpoints, and inspect variables, as long as you provide input in the right way (either manually inside GDB or through redirection outside GDB).

By using these steps, you should be able to debug your program and provide the necessary input without encountering the problem of input being misinterpreted as GDB commands.