mirror-llvm-project/lldb/test/API/macosx/lc-note/additional-registers/TestMetadataRegisters.py
Charles Zablit 67a20745d6
[lldb] Introduce the require decorator (#212753)
Currently, it is unclear if a test that is skipped is either:
- Unsupported because it will never run (macosx tests should not run on
Windows).
- Skipped because it's supposed to work but does not yet.
`@expectedFailure` is not always an option because a test might be
timing out and waiting 600s for it to fail is not acceptable.

This patch introduces 2 new decorators to differentiate those tests:
- `@requireX` meaning the tests require X to run (e.g `@requireDarwin`).
- `@requireNotX` meaning the tests requires anything but `X` to run (e.g
`@requireNotDarwin`).

In the tests results summary, this introduces a new category: `skipped`
tests:
- `@requireX` -> `UNSUPPORTED`
- `@skipIfX` -> `SKIPPED`

Here is how they can and cannot be stacked:

This will never run:
```py3
@requireDarwin
@requireWindows
def test():
    ...
```

This will not run on Linux, because `@requireWindows` is not satisfied.
```py3
@requireNotDarwin
@requireWindows
def test():
    ...
```

For "require Darwin or Windows", you need:
```py3
@requirePlatform(["darwin", "windows"])
def test():
    ...
```

For "require Darwin on ARM64 or Windows on ARM64", you need:
```py3
@requireARM64
@requirePlatform(["darwin", "windows"])
def test():
    ...
```

This patch also converts the tests in
`lldb/tests/API/{macosx,linux,windows}` to use these decorators. Patches
to convert the rest of the tests will follow.
2026-08-01 18:03:29 +02:00

150 lines
5.3 KiB
Python

"""Test that lldb will read additional registers from Mach-O LC_NOTE metadata."""
import os
import re
import subprocess
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class TestMetadataRegisters(TestBase):
NO_DEBUG_INFO_TESTCASE = True
@requireDarwin
@skipIfRemote
def test_add_registers_via_metadata(self):
self.build()
self.aout_exe = self.getBuildArtifact("a.out")
lldb_corefile = self.getBuildArtifact("lldb.core")
metadata_corefile = self.getBuildArtifact("metadata.core")
bad_metadata1_corefile = self.getBuildArtifact("bad-metadata1.core")
bad_metadata2_corefile = self.getBuildArtifact("bad-metadata2.core")
add_lcnote = self.getBuildArtifact("add-lcnote")
(target, process, t, bp) = lldbutil.run_to_source_breakpoint(
self, "break here", lldb.SBFileSpec("main.c")
)
self.assertTrue(process.IsValid())
if self.TraceOn():
self.runCmd("bt")
self.runCmd("reg read -a")
self.runCmd("process save-core " + lldb_corefile)
process.Kill()
target.Clear()
cmd = (
add_lcnote
+ " -r"
+ " -i '%s'" % lldb_corefile
+ " -o '%s'" % metadata_corefile
+ " -n 'process metadata' "
+ " -s '"
+ """{"threads":[{"register_info":
{"sets":["Special Registers", "General Purpose Registers"],
"registers":[
{"name":"jar", "value":10, "bitsize": 32, "set": 0},
{"name":"bar", "value":65537, "bitsize":16, "set":0},
{"name":"mar", "value":65537, "bitsize":32, "set":0},
{"name":"anotherpc", "value":55, "bitsize":64, "set": 1}]}}]}"""
+ "'"
)
call(cmd, shell=True)
cmd = (
add_lcnote
+ " -r"
+ " -i '%s'" % lldb_corefile
+ " -o '%s'" % bad_metadata1_corefile
+ " -n 'process metadata' "
+ " -s '"
+ """{lol im bad json}"""
+ "'"
)
call(cmd, shell=True)
cmd = (
add_lcnote
+ " -r"
+ " -i '%s'" % lldb_corefile
+ " -o '%s'" % bad_metadata2_corefile
+ " -n 'process metadata' "
+ " -s '"
+ """{"threads":[
{"register_info":
{"sets":["a"],"registers":[{"name":"a", "value":1, "bitsize": 32, "set": 0}]}},
{"register_info":
{"sets":["a"],"registers":[{"name":"a", "value":1, "bitsize": 32, "set": 0}]}}
]}"""
+ "'"
)
call(cmd, shell=True)
# Now load the corefile
target = self.dbg.CreateTarget("")
process = target.LoadCore(metadata_corefile)
self.assertTrue(process.IsValid())
if self.TraceOn():
self.runCmd("bt")
self.runCmd("reg read -a")
thread = process.GetSelectedThread()
frame = thread.GetFrameAtIndex(0)
# Register sets will be
# from LC_THREAD:
# General Purpose Registers
# Floating Point Registers
# Exception State Registers
# from LC_NOTE metadata:
# Special Registers
self.assertEqual(frame.registers[0].GetName(), "General Purpose Registers")
self.assertEqual(frame.registers[3].GetName(), "Special Registers")
anotherpc = frame.registers[0].GetChildMemberWithName("anotherpc")
self.assertTrue(anotherpc.IsValid())
self.assertEqual(anotherpc.GetValueAsUnsigned(), 0x37)
jar = frame.registers[3].GetChildMemberWithName("jar")
self.assertTrue(jar.IsValid())
self.assertEqual(jar.GetValueAsUnsigned(), 10)
self.assertEqual(jar.GetByteSize(), 4)
bar = frame.registers[3].GetChildMemberWithName("bar")
self.assertTrue(bar.IsValid())
self.assertEqual(bar.GetByteSize(), 2)
mar = frame.registers[3].GetChildMemberWithName("mar")
self.assertTrue(mar.IsValid())
self.assertEqual(mar.GetValueAsUnsigned(), 0x10001)
self.assertEqual(mar.GetByteSize(), 4)
# bad1 has invalid JSON, no additional registers
target = self.dbg.CreateTarget("")
process = target.LoadCore(bad_metadata1_corefile)
self.assertTrue(process.IsValid())
thread = process.GetSelectedThread()
frame = thread.GetFrameAtIndex(0)
gpr_found = False
for regset in frame.registers:
if regset.GetName() == "General Purpose Registers":
gpr_found = True
self.assertTrue(gpr_found)
# bad2 has invalid JSON, more process metadata threads than
# LC_THREADs, and should be rejected.
target = self.dbg.CreateTarget("")
process = target.LoadCore(bad_metadata2_corefile)
self.assertTrue(process.IsValid())
thread = process.GetSelectedThread()
frame = thread.GetFrameAtIndex(0)
metadata_regset_found = False
for regset in frame.registers:
if regset.GetName() == "a" or regset.GetName() == "b":
metadata_regset_found = True
self.assertFalse(metadata_regset_found)