Skip to content

Add gdb-repr directive for tests/debuginfo - #160377

Open
Walnut356 wants to merge 5 commits into
rust-lang:mainfrom
Walnut356:gdb_di_repr
Open

Add gdb-repr directive for tests/debuginfo#160377
Walnut356 wants to merge 5 commits into
rust-lang:mainfrom
Walnut356:gdb_di_repr

Conversation

@Walnut356

@Walnut356 Walnut356 commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

View all comments

Part of #148483 and followup to #158298. Applies (approximately) identical logic to GDB.

I still need to test things on windows-gnu (and locally try a few more tests to see if there's any glaring issues). There's also a few bike-sheddy things.

The main way this differs from the LLDB implementation is that GDB doesn't use lldb_batchmode/runner.py to orchestrate the commands. Instead, I have compiletest import from_gdb.py which registers a custom repr CLI command. GDB's batch processing works as normal, but dispatches to our logic automatically whenever it encounters repr <var_name>.

An additional repr-finalize CLI command is also registered to implement the checks that ensure we encountered all expected types/vars, and verifies that there were no errors before saving blessed data.

r? @Kobzol, @jieyouxu

@rustbot

rustbot commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Kobzol is not on the review rotation at the moment.
They may take a while to respond.

@rustbot rustbot added A-compiletest Area: The compiletest test runner A-testsuite Area: The testsuite used to check the correctness of rustc S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Aug 2, 2026
Comment thread src/etc/lldb_batchmode/check_gdb.py Outdated
Comment on lines +35 to +76
class ReprCommand(gdb.Command):
def __init__(self):
super().__init__("repr", gdb.COMMAND_OBSCURE)

def invoke(self, argument: str, from_tty: bool):
print(f"(gdb) repr {argument}")

global REPR_COMMAND_RUN
REPR_COMMAND_RUN = True
try:
if check(argument) == Result.Mismatch:
global REPR_ERROR
REPR_ERROR = True
except Exception as e:
import sys
import traceback

traceback.print_exception(type(e), e, e.__traceback__, file=sys.stdout)
gdb.execute("exit 1")


ReprCommand()


class ReprFinalize(gdb.Command):
def __init__(self):
super().__init__("repr_finalize", gdb.COMMAND_OBSCURE)

def invoke(self, argument: str, from_tty: bool):
if not REPR_COMMAND_RUN:
return

if not tested_all_variables() or not tested_all_types():
gdb.execute("exit 1")

if BLESS and not REPR_ERROR:
gdb_version = gdb.execute("show version", to_string=True).splitlines()[0]
metadata = BlessMetadata(sys.version, gdb_version)
INPUT_DATA.save_blessing(metadata)


ReprFinalize()

@Walnut356 Walnut356 Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's where we create and register the custom CLI commands.

View changes since the review

Comment on lines +519 to +579
TYPES_TESTED: dict[str, Result] = {}
"""Since types are unique and unchanging, we only need to test each type once. This also helps
ensure we have tested all types in `INPUT_DATA`
"""


VARS_TESTED: list[dict[str, Result]] = []
"""Used to help ensure all expected variables were tested. Each element of the list corresponds to a
breakpoint, and contains a set of all of the variable names tested for that breakpoint."""


def tested_all_types() -> bool:
"""Returns true if all types in INPUT_DATA were tested this run."""

expected_types = set(INPUT_DATA.types)
untested_types = expected_types.difference(TYPES_TESTED.keys())

if len(untested_types) != 0:
print(
f"{ANSI_RED}[repr error]{ANSI_END} The following types were expected, but were not \
tested:\n {untested_types}"
)

return len(untested_types) == 0


def tested_all_variables() -> bool:
expected_vars = [set(vars) for vars in INPUT_DATA.breakpoints]
untested_vars = [
expected.difference(tested.keys())
for expected, tested in zip(expected_vars, VARS_TESTED)
]

tested_not_expected = [
set(tested.keys()).difference(expected)
for expected, tested in zip(expected_vars, VARS_TESTED)
]

result = True

for i, v in enumerate(untested_vars):
if len(v) == 0:
continue

result = False
print(
f"{ANSI_RED}[repr error]{ANSI_END} The following variables were expected at \
breakpoint#{i}, but were not tested:\n {v}"
)

for i, v in enumerate(tested_not_expected):
if len(v) == 0:
continue

result = False
print(
f"{ANSI_RED}[repr error]{ANSI_END} The following variables were tested, but do not \
exist in the input data at breakpoint#{i}:\n {v}"
)

return result

@Walnut356 Walnut356 Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were just moved from check_lldb.py.

I might be able to factor more of the checking logic out and share it between lldb and gdb. There are less differences for their API than I was expecting. It would probably require passing a few wrappers to the check function that abstract away the debugger-specific accesses, but we'll see.

View changes since the review

gdb.args(debugger_opts).env("PYTHONPATH", pythonpath);
gdb.args(debugger_opts)
.env("PYTHONPATH", pythonpath)
.env("BATCHMODE_DEBUGGER", "gdb")

@Walnut356 Walnut356 Aug 2, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The bike-shedding I mentioned more or less has to do with these env vars and the lldb_batchmode package. With GDB support, we'll probably want to re-name lldb_batchmode (and probably rename runner.py to lldb_batchmode.py), but I'm not super happy with any of the names that came to mind. Maybe just batchmode?

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Batchmode sounds really opaque. I would suggest BATCHMODE => DEBUGGER_TESTER, or something like that.

@rust-log-analyzer

This comment has been minimized.

@Walnut356

Copy link
Copy Markdown
Contributor Author

Oh yeah, i need to gate it so it doesn't check for the file path until a repr command has been run

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-bors

This comment has been minimized.

@Walnut356
Walnut356 force-pushed the gdb_di_repr branch 2 times, most recently from 77e4567 to 170c054 Compare August 23, 2026 05:32
@Walnut356

Copy link
Copy Markdown
Contributor Author

There's probably more I can refactor to share more code between LLDB and GDB, but for now it should be good enough.

@Walnut356
Walnut356 marked this pull request as ready for review August 23, 2026 05:34
@rustbot

rustbot commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred in src/tools/compiletest

cc @jieyouxu

compiletest directives have been modified. Please add or update docs for the
new or modified directive in src/doc/rustc-dev-guide/.

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Aug 23, 2026

@Kobzol Kobzol left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like a non-trivial amount of code is shared with LLDB, that's good! Left some comments.

I tried it locally with GDB 15.1, and it failed with the following:

compiletest output
failures:

---- [debuginfo-gdb] tests/debuginfo/basic-types/main.rs stdout ----
NOTE: compiletest thinks it is using GDB version 15001000
------gdb stdout------------------------------
GNU gdb (Ubuntu 15.1-1ubuntu1~24.04.1) 15.1
Copyright (C) 2024 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".
To enable execution of this file add
        add-auto-load-safe-path /projects/personal/rust/rust/src/etc/gdb_load_rust_pretty_printers.py
line to your configuration file "/home/kobzol/.config/gdb/gdbinit".
To completely disable this security protection add
        set auto-load safe-path /
line to your configuration file "/home/kobzol/.config/gdb/gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual.  E.g., run from the shell:
        info "(gdb)Auto-loading safe path"
Breakpoint 1 at 0x1a81: file tests/debuginfo/basic-types/main.rs, line 112.

This GDB supports auto-downloading debuginfo from the following URLs:
  <https://debuginfod.ubuntu.com>
Enable debuginfod for this session? (y or [n]) [answered N; input not from terminal]
Debuginfod has been disabled.
To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main::main () at tests/debuginfo/basic-types/main.rs:112
112         _zzz(); // #break

------gdb stderr------------------------------
warning: File "/projects/personal/rust/rust/src/etc/gdb_load_rust_pretty_printers.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
Python Exception <class 'RuntimeError'>: pretty-printer already registered: builtin
/projects/personal/rust/rust/build/x86_64-unknown-linux-gnu/test/debuginfo/basic-types/main.gdb/main.debugger.script:10: Error in sourced command file:
Error occurred in Python: pretty-printer already registered: builtin

------------------------------------------

error: gdb failed to execute
status: exit status: 1
command: BATCHMODE_DEBUGGER="gdb" LLDB_BATCHMODE_BLESS_TEST_DATA="0" LLDB_BATCHMODE_INPUT_DATA_PATH="/projects/personal/rust/rust/tests/debuginfo/basic-types/gdb_input/non_windows.json" LLDB_BATCHMODE_TARGET_TRIPLE="x86_64-unknown-linux-gnu" PYTHONPATH="/projects/personal/rust/rust/src/etc" "gdb" "-quiet" "-batch" "-nx" "-command=/projects/personal/rust/rust/build/x86_64-unknown-linux-gnu/test/debuginfo/basic-types/main.gdb/main.debugger.script"
--- stdout -------------------------------
GNU gdb (Ubuntu 15.1-1ubuntu1~24.04.1) 15.1
Copyright (C) 2024 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".
To enable execution of this file add
        add-auto-load-safe-path /projects/personal/rust/rust/src/etc/gdb_load_rust_pretty_printers.py
line to your configuration file "/home/kobzol/.config/gdb/gdbinit".
To completely disable this security protection add
        set auto-load safe-path /
line to your configuration file "/home/kobzol/.config/gdb/gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual.  E.g., run from the shell:
        info "(gdb)Auto-loading safe path"
Breakpoint 1 at 0x1a81: file tests/debuginfo/basic-types/main.rs, line 112.

This GDB supports auto-downloading debuginfo from the following URLs:
  <https://debuginfod.ubuntu.com>
Enable debuginfod for this session? (y or [n]) [answered N; input not from terminal]
Debuginfod has been disabled.
To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, main::main () at tests/debuginfo/basic-types/main.rs:112
112         _zzz(); // #break
------------------------------------------
--- stderr -------------------------------
warning: File "/projects/personal/rust/rust/src/etc/gdb_load_rust_pretty_printers.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
Python Exception <class 'RuntimeError'>: pretty-printer already registered: builtin
/projects/personal/rust/rust/build/x86_64-unknown-linux-gnu/test/debuginfo/basic-types/main.gdb/main.debugger.script:10: Error in sourced command file:
Error occurred in Python: pretty-printer already registered: builtin
------------------------------------------

---- [debuginfo-gdb] tests/debuginfo/basic-types/main.rs stdout end ----

failures:
    [debuginfo-gdb] tests/debuginfo/basic-types/main.rs

View changes since this review

Comment thread src/etc/lldb_batchmode/__init__.py Outdated
Comment thread src/etc/debugger_tester/gdb/check_gdb.py
Comment on lines +141 to +145
summary_ok
& synthetic_ok
& format_ok
& pretty_type_name_ok
& pretty_print_ok,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
summary_ok
& synthetic_ok
& format_ok
& pretty_type_name_ok
& pretty_print_ok,
summary_ok
and synthetic_ok
and format_ok
and pretty_type_name_ok
and pretty_print_ok,

gdb.args(debugger_opts).env("PYTHONPATH", pythonpath);
gdb.args(debugger_opts)
.env("PYTHONPATH", pythonpath)
.env("BATCHMODE_DEBUGGER", "gdb")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Batchmode sounds really opaque. I would suggest BATCHMODE => DEBUGGER_TESTER, or something like that.

@Walnut356

Copy link
Copy Markdown
Contributor Author

I tried it locally with GDB 15.1, and it failed with the following:

Hmmm. I don't have super easy access to gdb 15 atm, but my best guess is it's a bug with importing GDB twice in the same script? OTOH it seems like CI runs gdb 16.3 anyway, so we should be able to just min-gdb-version and call it good.

@rustbot

rustbot commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred in tests/debuginfo/basic-stepping.rs

cc @Enselic

@rustbot rustbot added the A-tidy Area: The tidy tool label Aug 28, 2026
@rustbot

This comment has been minimized.

@Kobzol

Kobzol commented Aug 28, 2026

Copy link
Copy Markdown
Member

@bors try jobs=x86_64-gnu

@rust-bors

This comment has been minimized.

rust-bors Bot pushed a commit that referenced this pull request Aug 28, 2026
Add `gdb-repr` directive for `tests/debuginfo`


try-job: x86_64-gnu
@rust-bors

rust-bors Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

☀️ Try build successful (CI)
Build commit: a89712a (a89712a45cefece5e40b923d3e1de428cc2173fb)
Base parent: 344f790 (344f7902949345394fa40a5d7dda31f012ccbc0d)

@Walnut356

Copy link
Copy Markdown
Contributor Author

(just adding the min-gdb-version)

@Kobzol Kobzol left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, the restructuralization looks good to me. I'll let @jieyouxu take a look too.

View changes since this review

@jieyouxu jieyouxu self-assigned this Aug 30, 2026
@jieyouxu

Copy link
Copy Markdown
Member

(Out today but have time tmrw)

JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 30, 2026
Rerun `tests/debuginfo` tests if repr data has changed

Resolves rust-lang#161138

This also includes the necessary checking for GDB's data even though none exists atm (rust-lang#160377 will contain the first set). The extra handling doesn't hurt anything since we have to account for all the other tests that don't have repr data anyway.

In a followup, I can rename the `lldb_input` directory to something else (see: rust-lang#160137 (comment)). Doing so requires me to touch a bunch of other places where the name is used, so it should probably be it's own PR. Making sure the tests rerun when the data changes is higher priority though atm.

r? @jieyouxu , @Kobzol

cc @Mark-Simulacrum
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 30, 2026
Rerun `tests/debuginfo` tests if repr data has changed

Resolves rust-lang#161138

This also includes the necessary checking for GDB's data even though none exists atm (rust-lang#160377 will contain the first set). The extra handling doesn't hurt anything since we have to account for all the other tests that don't have repr data anyway.

In a followup, I can rename the `lldb_input` directory to something else (see: rust-lang#160137 (comment)). Doing so requires me to touch a bunch of other places where the name is used, so it should probably be it's own PR. Making sure the tests rerun when the data changes is higher priority though atm.

r? @jieyouxu , @Kobzol

cc @Mark-Simulacrum
rust-bors Bot pushed a commit that referenced this pull request Aug 30, 2026
Rollup merge of #161967 - Walnut356:stamp_repr_data, r=jieyouxu

Rerun `tests/debuginfo` tests if repr data has changed

Resolves #161138

This also includes the necessary checking for GDB's data even though none exists atm (#160377 will contain the first set). The extra handling doesn't hurt anything since we have to account for all the other tests that don't have repr data anyway.

In a followup, I can rename the `lldb_input` directory to something else (see: #160137 (comment)). Doing so requires me to touch a bunch of other places where the name is used, so it should probably be it's own PR. Making sure the tests rerun when the data changes is higher priority though atm.

r? @jieyouxu , @Kobzol

cc @Mark-Simulacrum
@rust-bors

This comment has been minimized.

@rustbot

rustbot commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Walnut356

Walnut356 commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

I also added the GDB equivalents for "don't fully fail on types" from #161574 and dumping raw json in CI from #162002

@rust-log-analyzer

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-compiletest Area: The compiletest test runner A-testsuite Area: The testsuite used to check the correctness of rustc A-tidy Area: The tidy tool S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-bootstrap Relevant to the bootstrap subteam: Rust's build system (x.py and src/bootstrap) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants