Skip to content

Commit e90edbc

Browse files
committed
feat(gdb): add detailed timing logs for GDB operations
Add [GDB] prefixed logs to all GDB session methods: - _execute_cli: log slow commands (>1s as warning, others as debug) - _lookup_symbol_impl: log start/done with address and timing - _search_symbols_impl: log query, result count, and timing - _resolve_addresses: log unresolved count and resolution stats - _get_struct_layout_impl: log member count and timing Add [symbols] prefixed logs to route handlers: - _lookup_symbol: log GDB lookup timing - api_search_symbols: log search delegation and results Signed-off-by: VIFEX <vifextech@foxmail.com>
1 parent b71e44b commit e90edbc

2 files changed

Lines changed: 77 additions & 1 deletion

File tree

Tools/WebServer/app/routes/symbols.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,14 @@ def _lookup_symbol(sym_name):
135135
logger.warning("GDB not available, cannot look up symbol")
136136
return None
137137

138+
t0 = time.time()
138139
result = state.gdb_session.lookup_symbol(sym_name)
140+
elapsed = time.time() - t0
141+
142+
if elapsed > 1.0:
143+
logger.warning(f"[symbols] GDB lookup_symbol '{sym_name}' took {elapsed:.2f}s")
144+
else:
145+
logger.info(f"[symbols] GDB lookup_symbol '{sym_name}': {elapsed:.3f}s")
139146

140147
# Cache for future lookups
141148
if result is not None:
@@ -179,6 +186,8 @@ def api_search_symbols():
179186

180187
query = request.args.get("q", "").strip()
181188
limit = int(request.args.get("limit", 100))
189+
t_start = time.time()
190+
logger.info(f"[symbols] search request: query='{query}' limit={limit}")
182191

183192
if not query:
184193
return jsonify({"success": True, "symbols": [], "total": 0, "filtered": 0})
@@ -220,7 +229,13 @@ def api_search_symbols():
220229
symbol_list = matched[:limit]
221230
elif is_gdb_available(state):
222231
# GDB fast search (~0.01s vs ~3s)
232+
logger.info(f"[symbols] delegating search to GDB: '{query}'")
223233
symbol_list, total = state.gdb_session.search_symbols(query, limit=limit)
234+
elapsed = time.time() - t_start
235+
logger.info(
236+
f"[symbols] GDB search done: '{query}' -> "
237+
f"{len(symbol_list)} results ({elapsed:.3f}s)"
238+
)
224239
else:
225240
symbol_list, total = [], 0
226241
logger.warning("GDB not available, cannot search symbols")

Tools/WebServer/core/gdb_session.py

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,9 +331,16 @@ def _execute_mi(self, cmd: str, timeout: float = GDB_CMD_TIMEOUT) -> Optional[st
331331

332332
def _execute_cli(self, cmd: str, timeout: float = GDB_CMD_TIMEOUT) -> Optional[str]:
333333
"""Execute a GDB CLI command and return console output lines."""
334+
t0 = time.time()
334335
raw = self._execute_mi(cmd, timeout)
336+
elapsed = time.time() - t0
335337
if raw is None:
338+
logger.warning(f"[GDB] command timed out ({elapsed:.2f}s): {cmd}")
336339
return None
340+
if elapsed > 1.0:
341+
logger.warning(f"[GDB] slow command ({elapsed:.2f}s): {cmd}")
342+
else:
343+
logger.debug(f"[GDB] command ({elapsed:.3f}s): {cmd}")
337344
return self._extract_console_output(raw)
338345

339346
def _read_until_prompt(self, timeout: float = 5.0) -> Optional[str]:
@@ -415,13 +422,20 @@ def _extract_console_output(raw: str) -> str:
415422

416423
def _lookup_symbol_impl(self, sym_name: str) -> Optional[dict]:
417424
"""Internal implementation of lookup_symbol."""
425+
t_start = time.time()
426+
logger.info(f"[GDB] lookup_symbol start: '{sym_name}'")
427+
418428
# Use 'info address' to get symbol address
419429
output = self._execute_cli(f"info address {sym_name}")
420430
if not output or "No symbol" in output:
431+
logger.info(f"[GDB] lookup_symbol: '{sym_name}' not found")
421432
return None
422433

423434
addr = self._parse_address_from_info(output)
424435
if addr is None:
436+
logger.warning(
437+
f"[GDB] lookup_symbol: cannot parse address for '{sym_name}'"
438+
)
425439
return None
426440

427441
# Get size via 'print sizeof(sym_name)'
@@ -445,6 +459,12 @@ def _lookup_symbol_impl(self, sym_name: str) -> Optional[dict]:
445459
if ptype_out and re.match(r"type\s*=\s*const\b", ptype_out):
446460
sym_type = "const"
447461

462+
elapsed = time.time() - t_start
463+
logger.info(
464+
f"[GDB] lookup_symbol done: '{sym_name}' -> "
465+
f"0x{addr:08X} size={size} type={sym_type} ({elapsed:.3f}s)"
466+
)
467+
448468
return {
449469
"addr": addr,
450470
"size": size,
@@ -456,6 +476,8 @@ def _search_symbols_impl(
456476
self, query: str, limit: int = 100
457477
) -> Tuple[List[dict], int]:
458478
"""Internal implementation of search_symbols."""
479+
t_start = time.time()
480+
logger.info(f"[GDB] search_symbols start: query='{query}' limit={limit}")
459481
query_lower = query.lower().strip()
460482
is_addr = query_lower.startswith("0x") or (
461483
len(query_lower) >= 4 and all(c in "0123456789abcdef" for c in query_lower)
@@ -498,10 +520,21 @@ def _search_symbols_impl(
498520
seen.add(r["name"])
499521
unique.append(r)
500522

523+
t_parse = time.time()
524+
logger.info(
525+
f"[GDB] search_symbols: found {len(unique)} unique symbols, "
526+
f"resolving addresses... (parse took {t_parse - t_start:.3f}s)"
527+
)
528+
501529
# Resolve missing addresses via 'info address'
502530
self._resolve_addresses(unique)
503531

504532
unique.sort(key=lambda x: x["name"])
533+
elapsed = time.time() - t_start
534+
logger.info(
535+
f"[GDB] search_symbols done: query='{query}' -> "
536+
f"{len(unique)} results ({elapsed:.3f}s)"
537+
)
505538
return unique[:limit], len(unique)
506539

507540
def _get_symbols_impl(self) -> Dict[str, dict]:
@@ -551,15 +584,27 @@ def _get_struct_layout_impl(self, sym_name: str) -> Optional[List[dict]]:
551584
552585
Uses 'ptype /o <sym>' which shows struct members with offsets.
553586
"""
587+
t0 = time.time()
588+
logger.info(f"[GDB] get_struct_layout start: '{sym_name}'")
589+
554590
output = self._execute_cli(f"ptype /o {sym_name}")
555591
if not output:
592+
logger.info(f"[GDB] get_struct_layout: no output for '{sym_name}'")
556593
return None
557594

558595
# Check if it's a struct/union
559596
if "type = struct" not in output and "type = union" not in output:
597+
logger.info(f"[GDB] get_struct_layout: '{sym_name}' is not struct/union")
560598
return None
561599

562-
return self._parse_ptype_output(output)
600+
result = self._parse_ptype_output(output)
601+
elapsed = time.time() - t0
602+
member_count = len(result) if result else 0
603+
logger.info(
604+
f"[GDB] get_struct_layout done: '{sym_name}' -> "
605+
f"{member_count} members ({elapsed:.3f}s)"
606+
)
607+
return result
563608

564609
def _read_symbol_value_impl(self, sym_name: str) -> Optional[bytes]:
565610
"""Internal implementation of read_symbol_value.
@@ -627,6 +672,14 @@ def _resolve_addresses(self, symbols: List[dict]):
627672
addresses. This method queries 'info address <name>' for each symbol
628673
with addr "0x00000000" to fill in the real address and section.
629674
"""
675+
unresolved = [s for s in symbols if s["addr"] == "0x00000000"]
676+
if unresolved:
677+
logger.info(
678+
f"[GDB] _resolve_addresses: {len(unresolved)}/{len(symbols)} "
679+
f"symbols need address resolution"
680+
)
681+
t0 = time.time()
682+
resolved_count = 0
630683
for sym in symbols:
631684
if sym["addr"] != "0x00000000":
632685
continue
@@ -636,6 +689,7 @@ def _resolve_addresses(self, symbols: List[dict]):
636689
addr = self._parse_address_from_info(output)
637690
if addr is not None:
638691
sym["addr"] = f"0x{addr:08X}"
692+
resolved_count += 1
639693
# Also fix section and type from info address output
640694
section = self._get_symbol_section(output)
641695
if section:
@@ -650,6 +704,13 @@ def _resolve_addresses(self, symbols: List[dict]):
650704
# Preserve const classification from declaration
651705
sym["type"] = "variable"
652706

707+
if unresolved:
708+
elapsed = time.time() - t0
709+
logger.info(
710+
f"[GDB] _resolve_addresses done: resolved {resolved_count}/{len(unresolved)} "
711+
f"({elapsed:.3f}s)"
712+
)
713+
653714
@staticmethod
654715
def _parse_address_from_info(output: str) -> Optional[int]:
655716
"""Parse address from 'info address' output.

0 commit comments

Comments
 (0)