Skip to content

Commit a3f0d88

Browse files
committed
fix: use GDB session for symbol lookup in inject workflow
Replace stubbed get_symbols() calls in inject() and inject_multi() with _resolve_symbol_addr() that queries GDB session directly. This fixes 'Target function not found in ELF' and symbol address=0 bugs introduced by the pyelftools removal refactor.
1 parent 3d580f5 commit a3f0d88

2 files changed

Lines changed: 84 additions & 53 deletions

File tree

Tools/WebServer/fpb_inject.py

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,25 @@ def get_symbols(self, elf_path: str) -> Dict[str, dict]:
242242
"""
243243
return {}
244244

245+
def _resolve_symbol_addr(self, sym_name: str) -> Optional[int]:
246+
"""Resolve a symbol name to its address via GDB session.
247+
248+
Returns the address as int, or None if not found.
249+
"""
250+
from core.state import state
251+
from core.gdb_manager import is_gdb_available
252+
253+
if not is_gdb_available(state):
254+
logger.warning("GDB not available, cannot resolve symbol address")
255+
return None
256+
257+
info = state.gdb_session.lookup_symbol(sym_name)
258+
if info is None:
259+
return None
260+
261+
addr = info["addr"] if isinstance(info, dict) else info
262+
return addr
263+
245264
def disassemble_function(self, elf_path: str, func_name: str) -> Tuple[bool, str]:
246265
"""Disassemble a specific function from ELF file."""
247266
return elf_utils.disassemble_function(elf_path, func_name, self._toolchain_path)
@@ -416,11 +435,10 @@ def inject(
416435
if not elf_path or not os.path.exists(elf_path):
417436
return False, {"error": "ELF file not found"}
418437

419-
symbols = self.get_symbols(elf_path)
420-
if target_func not in symbols:
438+
target_addr = self._resolve_symbol_addr(target_func)
439+
if target_addr is None:
421440
return False, {"error": f"Target function '{target_func}' not found in ELF"}
422441

423-
target_addr = symbols[target_func]
424442
result["target_addr"] = f"0x{target_addr:08X}"
425443

426444
actual_comp = comp
@@ -592,8 +610,6 @@ def inject_multi(
592610
if not elf_path or not os.path.exists(elf_path):
593611
return False, {"error": "ELF file not found"}
594612

595-
elf_symbols = self.get_symbols(elf_path)
596-
597613
data, inject_symbols, error = self.compile_inject(
598614
source_content=source_content,
599615
base_addr=0x20000000,
@@ -632,22 +648,15 @@ def inject_multi(
632648
# In new design, inject_name IS the target function name
633649
target_func = inject_name
634650

635-
target_addr = None
636-
actual_target_name = target_func
637-
for sym_name, sym_addr in elf_symbols.items():
638-
if sym_name.lower() == target_func.lower():
639-
target_addr = sym_addr
640-
actual_target_name = sym_name
641-
break
642-
651+
target_addr = self._resolve_symbol_addr(target_func)
643652
if target_addr is None:
644653
result["errors"].append(f"Target '{target_func}' not found in ELF")
645654
logger.warning(
646655
f"Target function '{target_func}' not found in ELF symbols"
647656
)
648657
continue
649658

650-
injection_targets.append((actual_target_name, inject_name))
659+
injection_targets.append((target_func, inject_name))
651660

652661
if not injection_targets:
653662
return False, {"error": "No valid injection targets found"}

Tools/WebServer/tests/test_fpb_inject.py

Lines changed: 61 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,8 +1502,8 @@ def test_inject_no_symbols(self):
15021502
self.device.elf_path = f.name
15031503

15041504
try:
1505-
with patch.object(self.fpb, "get_symbols") as mock_syms:
1506-
mock_syms.return_value = {} # Empty symbols
1505+
with patch.object(self.fpb, "_resolve_symbol_addr") as mock_resolve:
1506+
mock_resolve.return_value = None # Symbol not found
15071507

15081508
success, result = self.fpb.inject("source", "target_func")
15091509

@@ -1520,13 +1520,15 @@ def test_inject_compile_fail(self, mock_compile):
15201520
self.device.elf_path = f.name
15211521

15221522
try:
1523-
with patch.object(self.fpb, "get_symbols") as mock_syms, patch.object(
1523+
with patch.object(
1524+
self.fpb, "_resolve_symbol_addr"
1525+
) as mock_resolve, patch.object(
15241526
self.fpb, "info"
15251527
) as mock_info, patch.object(
15261528
self.fpb, "find_slot_for_target"
15271529
) as mock_find_slot:
15281530

1529-
mock_syms.return_value = {"target_func": 0x08000000}
1531+
mock_resolve.return_value = 0x08000000
15301532
mock_info.return_value = ({"base": 0x20000000}, "")
15311533
mock_find_slot.return_value = (
15321534
0,
@@ -1555,13 +1557,17 @@ def test_inject_success_flow(
15551557
self.device.elf_path = f.name
15561558

15571559
try:
1558-
with patch.object(self.fpb, "get_symbols") as mock_syms, patch.object(
1560+
with patch.object(
1561+
self.fpb, "_resolve_symbol_addr"
1562+
) as mock_resolve, patch.object(
15591563
self.fpb, "info"
1560-
) as mock_info, patch.object(self.fpb, "alloc") as mock_alloc, patch.object(
1564+
) as mock_info, patch.object(
1565+
self.fpb, "alloc"
1566+
) as mock_alloc, patch.object(
15611567
self.fpb, "find_slot_for_target"
15621568
) as mock_find_slot:
15631569

1564-
mock_syms.return_value = {"target_func": 0x08000000}
1570+
mock_resolve.return_value = 0x08000000
15651571
mock_info.return_value = ({"used": 0}, "")
15661572
mock_alloc.return_value = (0x20000000, "")
15671573
mock_find_slot.return_value = (
@@ -1606,17 +1612,21 @@ def test_inject_dynamic_allocation(self, mock_compile):
16061612
self.device.elf_path = f.name
16071613

16081614
try:
1609-
with patch.object(self.fpb, "get_symbols") as mock_syms, patch.object(
1615+
with patch.object(
1616+
self.fpb, "_resolve_symbol_addr"
1617+
) as mock_resolve, patch.object(
16101618
self.fpb, "info"
1611-
) as mock_info, patch.object(self.fpb, "alloc") as mock_alloc, patch.object(
1619+
) as mock_info, patch.object(
1620+
self.fpb, "alloc"
1621+
) as mock_alloc, patch.object(
16121622
self.fpb, "find_slot_for_target"
16131623
) as mock_find_slot, patch.object(
16141624
self.fpb, "upload"
16151625
) as mock_upload, patch.object(
16161626
self.fpb, "tpatch"
16171627
) as mock_tpatch:
16181628

1619-
mock_syms.return_value = {"target_func": 0x08000000}
1629+
mock_resolve.return_value = 0x08000000
16201630
# info returns used memory
16211631
mock_info.return_value = (
16221632
{"used": 0},
@@ -1654,17 +1664,21 @@ def test_inject_finds_function_by_exact_name(self, mock_compile):
16541664
self.device.elf_path = f.name
16551665

16561666
try:
1657-
with patch.object(self.fpb, "get_symbols") as mock_syms, patch.object(
1667+
with patch.object(
1668+
self.fpb, "_resolve_symbol_addr"
1669+
) as mock_resolve, patch.object(
16581670
self.fpb, "info"
1659-
) as mock_info, patch.object(self.fpb, "alloc") as mock_alloc, patch.object(
1671+
) as mock_info, patch.object(
1672+
self.fpb, "alloc"
1673+
) as mock_alloc, patch.object(
16601674
self.fpb, "find_slot_for_target"
16611675
) as mock_find_slot, patch.object(
16621676
self.fpb, "upload"
16631677
) as mock_upload, patch.object(
16641678
self.fpb, "tpatch"
16651679
) as mock_tpatch:
16661680

1667-
mock_syms.return_value = {"digitalWrite": 0x08000100}
1681+
mock_resolve.return_value = 0x08000100
16681682
mock_info.return_value = ({"used": 0}, "")
16691683
mock_alloc.return_value = (0x20001000, "")
16701684
mock_find_slot.return_value = (0, False)
@@ -1692,13 +1706,17 @@ def test_inject_no_fpb_marked_function_error(self, mock_compile):
16921706
self.device.elf_path = f.name
16931707

16941708
try:
1695-
with patch.object(self.fpb, "get_symbols") as mock_syms, patch.object(
1709+
with patch.object(
1710+
self.fpb, "_resolve_symbol_addr"
1711+
) as mock_resolve, patch.object(
16961712
self.fpb, "info"
1697-
) as mock_info, patch.object(self.fpb, "alloc") as mock_alloc, patch.object(
1713+
) as mock_info, patch.object(
1714+
self.fpb, "alloc"
1715+
) as mock_alloc, patch.object(
16981716
self.fpb, "find_slot_for_target"
16991717
) as mock_find_slot:
17001718

1701-
mock_syms.return_value = {"target_func": 0x08000100}
1719+
mock_resolve.return_value = 0x08000100
17021720
mock_info.return_value = ({"used": 0}, "")
17031721
mock_alloc.return_value = (0x20001000, "")
17041722
mock_find_slot.return_value = (0, False)
@@ -1724,17 +1742,21 @@ def test_inject_fallback_to_first_symbol(self, mock_compile):
17241742
self.device.elf_path = f.name
17251743

17261744
try:
1727-
with patch.object(self.fpb, "get_symbols") as mock_syms, patch.object(
1745+
with patch.object(
1746+
self.fpb, "_resolve_symbol_addr"
1747+
) as mock_resolve, patch.object(
17281748
self.fpb, "info"
1729-
) as mock_info, patch.object(self.fpb, "alloc") as mock_alloc, patch.object(
1749+
) as mock_info, patch.object(
1750+
self.fpb, "alloc"
1751+
) as mock_alloc, patch.object(
17301752
self.fpb, "find_slot_for_target"
17311753
) as mock_find_slot, patch.object(
17321754
self.fpb, "upload"
17331755
) as mock_upload, patch.object(
17341756
self.fpb, "tpatch"
17351757
) as mock_tpatch:
17361758

1737-
mock_syms.return_value = {"some_func": 0x08000100}
1759+
mock_resolve.return_value = 0x08000100
17381760
mock_info.return_value = ({"used": 0}, "")
17391761
mock_alloc.return_value = (0x20001000, "")
17401762
mock_find_slot.return_value = (0, False)
@@ -2326,15 +2348,19 @@ def test_inject_multi_finds_functions_without_prefix(self, mock_compile):
23262348
self.device.elf_path = f.name
23272349

23282350
try:
2329-
with patch.object(self.fpb, "get_symbols") as mock_syms, patch.object(
2330-
self.fpb, "inject"
2331-
) as mock_inject:
2351+
with patch.object(
2352+
self.fpb, "_resolve_symbol_addr"
2353+
) as mock_resolve, patch.object(self.fpb, "inject") as mock_inject:
2354+
2355+
# _resolve_symbol_addr returns address for known functions
2356+
def resolve_side_effect(name):
2357+
addrs = {
2358+
"digitalWrite": 0x08000100,
2359+
"analogWrite": 0x08000200,
2360+
}
2361+
return addrs.get(name)
23322362

2333-
# Firmware has these functions
2334-
mock_syms.return_value = {
2335-
"digitalWrite": 0x08000100,
2336-
"analogWrite": 0x08000200,
2337-
}
2363+
mock_resolve.side_effect = resolve_side_effect
23382364

23392365
# Compiled patch has these symbols (same names, no prefix)
23402366
mock_compile.return_value = (
@@ -2361,17 +2387,13 @@ def test_inject_multi_no_symbols_error(self, mock_compile):
23612387
self.device.elf_path = f.name
23622388

23632389
try:
2364-
with patch.object(self.fpb, "get_symbols") as mock_syms:
2365-
2366-
mock_syms.return_value = {"some_func": 0x08000100}
2390+
# No symbols in compiled code
2391+
mock_compile.return_value = (b"\x00" * 100, {}, "")
23672392

2368-
# No symbols in compiled code
2369-
mock_compile.return_value = (b"\x00" * 100, {}, "")
2393+
success, result = self.fpb.inject_multi("source")
23702394

2371-
success, result = self.fpb.inject_multi("source")
2372-
2373-
self.assertFalse(success)
2374-
self.assertIn("No FPB_INJECT marked functions", result["error"])
2395+
self.assertFalse(success)
2396+
self.assertIn("No FPB_INJECT marked functions", result["error"])
23752397
finally:
23762398
if os.path.exists(self.device.elf_path):
23772399
os.remove(self.device.elf_path)
@@ -2383,10 +2405,10 @@ def test_inject_multi_target_not_in_elf(self, mock_compile):
23832405
self.device.elf_path = f.name
23842406

23852407
try:
2386-
with patch.object(self.fpb, "get_symbols") as mock_syms:
2408+
with patch.object(self.fpb, "_resolve_symbol_addr") as mock_resolve:
23872409

2388-
# Firmware doesn't have the function we're trying to patch
2389-
mock_syms.return_value = {"other_func": 0x08000100}
2410+
# Function not found in ELF
2411+
mock_resolve.return_value = None
23902412

23912413
# Compiled patch has this function
23922414
mock_compile.return_value = (

0 commit comments

Comments
 (0)