1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
"""Live integration smoke test: boots the demo uproc in QEMU.
Skipped cleanly when qemu-system-riscv64 or the demo firmware is absent.
"""
from __future__ import annotations
import os
import shutil
import unittest
import greeneye as ge
from greeneye.errors import GreenEyeError
from greeneye.probes import compile_condition, install
HERE = os.path.dirname(os.path.abspath(__file__))
DEMO_ELF = os.path.join(HERE, "..", "firmware", "uproc_demo", "build", "uproc_demo.elf")
def qemu_available() -> bool:
return bool(os.environ.get("GREENEYE_QEMU") or shutil.which("qemu-system-riscv64"))
@unittest.skipUnless(qemu_available(), "qemu-system-riscv64 not installed")
@unittest.skipUnless(os.path.exists(DEMO_ELF), "demo firmware not built (make demo)")
class QemuSmokeTests(unittest.TestCase):
def test_boot_hook_watch_snapshot_analyze(self):
session = ge.launch(kernel=DEMO_ELF, record=True, name="unittest-smoke")
hits = []
try:
ctrl = session.symbols.lookup("gsp_ctrl")
session.hook("rpc_sum", on_enter=lambda hit: hits.append(hit))
session.watch(ctrl + 16, size=8, kind="w")
session.run(duration=0.6)
self.assertTrue(session.target.wait_for_uart("GREEN-EYE UPROC DEMO", timeout=1.0))
self.assertGreaterEqual(len(hits), 1, "rpc_sum hook never fired")
after = session.snapshot(ctrl, 0x188, "ctrl")
self.assertEqual(int.from_bytes(after[0:4], "little"), 0x47535031)
self.assertGreaterEqual(int.from_bytes(after[16:24], "little"), 7)
finally:
directory = getattr(session.recorder, "dir", None)
session.close()
if directory:
from greeneye.analyze import render_summary
report = render_summary(directory)
self.assertIn("rpc_sum", report)
def test_probe_spec_install(self):
session = ge.launch(kernel=DEMO_ELF, name="unittest-probes")
try:
spec = {
"probes": [
{
"name": "sum",
"symbol": "rpc_sum",
"when": "a1 > 0",
"on_enter": {"log": ["a0", "a1"], "note": "sum called"},
}
]
}
handles = install(session, spec)
self.assertEqual(len(handles), 1)
session.run(duration=0.6)
self.assertEqual(handles[0].hits, 1) # self-test calls rpc_sum once
finally:
session.close()
def test_condition_guard(self):
self.assertIsNone(compile_condition(None))
check = compile_condition("a0 == 0x2a and a1 < 4")
self.assertTrue(check({"a0": 0x2A, "a1": 2}))
self.assertFalse(check({"a0": 0x2B, "a1": 2}))
with self.assertRaises(GreenEyeError):
compile_condition("__import__('os').system('true')")
if __name__ == "__main__":
unittest.main()
|