Skip to content

Commit 4be6cc6

Browse files
committed
fix(symbols): add c_type and decoded_value to all symbol read endpoints
- Extract c_type from sym_info in /symbols/read and /symbols/read/stream - Decode scalar values on backend using c_type for proper display - Render scalar variables using struct tree style for consistent UI - Fix NameError: 'c_type' not defined in device read endpoint
1 parent 80fe824 commit 4be6cc6

3 files changed

Lines changed: 81 additions & 7 deletions

File tree

Tools/WebServer/app/routes/symbols.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,13 @@ def _decode_field_value(raw_bytes: bytes, type_name: str):
182182
is_int = any(kw in type_lower for kw in _INT_TYPE_KEYWORDS)
183183
if is_int and size <= 8:
184184
val = int.from_bytes(raw_bytes, "little")
185-
# Signed check: type doesn't start with 'u'/'U' and doesn't contain 'uint'
185+
# Signed check: type doesn't start with 'u'/'U', doesn't contain 'uint',
186+
# and doesn't contain 'unsigned' (handles "long unsigned int" from DWARF)
186187
if (
187188
not type_name.startswith("u")
188189
and not type_name.startswith("U")
189190
and "uint" not in type_name
191+
and "unsigned" not in type_name
190192
):
191193
max_signed = 1 << (size * 8 - 1)
192194
if val >= max_signed:
@@ -796,6 +798,7 @@ def api_get_symbol_value():
796798
sym_info.get("type", "other") if isinstance(sym_info, dict) else "function"
797799
)
798800
section = sym_info.get("section", "") if isinstance(sym_info, dict) else ""
801+
c_type = sym_info.get("c_type") if isinstance(sym_info, dict) else None
799802
is_pointer = (
800803
sym_info.get("is_pointer", False) if isinstance(sym_info, dict) else False
801804
)
@@ -845,6 +848,14 @@ def api_get_symbol_value():
845848

846849
logger.info(f"[value] Total for '{sym_name}': {time.time() - t_start:.2f}s")
847850

851+
# Decode scalar value from hex_data using c_type when no struct layout
852+
decoded_value = None
853+
if hex_data and c_type and not struct_layout and not is_pointer:
854+
raw = bytes.fromhex(hex_data)
855+
decoded_value = _decode_field_value(raw, c_type)
856+
if decoded_value is None:
857+
decoded_value = _decode_field_value_fallback(raw, c_type)
858+
848859
resp = {
849860
"success": True,
850861
"name": sym_name,
@@ -856,6 +867,10 @@ def api_get_symbol_value():
856867
"struct_layout": struct_layout,
857868
"gdb_values": gdb_values,
858869
}
870+
if c_type:
871+
resp["c_type"] = c_type
872+
if decoded_value is not None:
873+
resp["decoded_value"] = decoded_value
859874
if is_pointer:
860875
resp["is_pointer"] = True
861876
resp["pointer_target"] = pointer_target
@@ -897,6 +912,7 @@ def api_read_symbol_from_device():
897912
pointer_target = (
898913
sym_info.get("pointer_target") if isinstance(sym_info, dict) else None
899914
)
915+
c_type = sym_info.get("c_type") if isinstance(sym_info, dict) else None
900916
if size <= 0:
901917
return jsonify(
902918
{"success": False, "error": f"Symbol '{sym_name}' has unknown size"}
@@ -934,6 +950,14 @@ def api_read_symbol_from_device():
934950
if struct_layout:
935951
gdb_values = _decode_struct_values(struct_layout, hex_data)
936952

953+
# Decode scalar value for non-struct, non-pointer types
954+
decoded_value = None
955+
if hex_data and c_type and not struct_layout and not is_pointer:
956+
raw = bytes.fromhex(hex_data)
957+
decoded_value = _decode_field_value(raw, c_type)
958+
if decoded_value is None:
959+
decoded_value = _decode_field_value_fallback(raw, c_type)
960+
937961
resp = {
938962
"success": True,
939963
"name": sym_name,
@@ -944,6 +968,10 @@ def api_read_symbol_from_device():
944968
"gdb_values": gdb_values,
945969
"source": "device",
946970
}
971+
if c_type:
972+
resp["c_type"] = c_type
973+
if decoded_value is not None:
974+
resp["decoded_value"] = decoded_value
947975
if is_pointer:
948976
resp["is_pointer"] = True
949977
resp["pointer_target"] = pointer_target
@@ -1038,6 +1066,7 @@ def api_read_symbol_stream():
10381066
pointer_target = (
10391067
sym_info.get("pointer_target") if isinstance(sym_info, dict) else None
10401068
)
1069+
c_type = sym_info.get("c_type") if isinstance(sym_info, dict) else None
10411070
if size <= 0:
10421071
return jsonify(
10431072
{"success": False, "error": f"Symbol '{sym_name}' has unknown size"}
@@ -1141,6 +1170,14 @@ def do_read_wrapper():
11411170
if struct_layout:
11421171
gdb_values = _decode_struct_values(struct_layout, hex_data)
11431172

1173+
# Decode scalar value for non-struct, non-pointer types
1174+
decoded_value = None
1175+
if hex_data and c_type and not struct_layout and not is_pointer:
1176+
raw = bytes.fromhex(hex_data)
1177+
decoded_value = _decode_field_value(raw, c_type)
1178+
if decoded_value is None:
1179+
decoded_value = _decode_field_value_fallback(raw, c_type)
1180+
11441181
resp = {
11451182
"type": "result",
11461183
"success": True,
@@ -1152,6 +1189,10 @@ def do_read_wrapper():
11521189
"gdb_values": gdb_values,
11531190
"source": "device",
11541191
}
1192+
if c_type:
1193+
resp["c_type"] = c_type
1194+
if decoded_value is not None:
1195+
resp["decoded_value"] = decoded_value
11551196
if is_pointer:
11561197
resp["is_pointer"] = True
11571198
resp["pointer_target"] = pointer_target

Tools/WebServer/core/gdb_session.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -540,15 +540,17 @@ def _lookup_symbol_impl(self, sym_name: str) -> Optional[dict]:
540540
if ptype_out and re.match(r"type\s*=\s*const\b", ptype_out):
541541
sym_type = "const"
542542

543-
# Detect pointer types via whatis (e.g. "type = lv_disp_t *")
543+
# Detect pointer types and C type name via whatis
544544
is_pointer = False
545545
pointer_target = None
546+
c_type = None
546547
if sym_type in ("variable", "const"):
547548
whatis_out = self._execute_cli(f"whatis {query_name}")
548549
if whatis_out:
549550
wm = re.match(r"type\s*=\s*(.+)", whatis_out.strip())
550551
if wm:
551552
raw_type = wm.group(1).strip()
553+
c_type = raw_type
552554
# Pointer if type ends with '*' (but not function pointer)
553555
if raw_type.endswith("*") and "(" not in raw_type:
554556
is_pointer = True
@@ -557,7 +559,7 @@ def _lookup_symbol_impl(self, sym_name: str) -> Optional[dict]:
557559
elapsed = time.time() - t_start
558560
logger.info(
559561
f"[GDB] lookup_symbol done: '{sym_name}' -> "
560-
f"0x{addr:08X} size={size} type={sym_type}"
562+
f"0x{addr:08X} size={size} type={sym_type} c_type={c_type}"
561563
f"{' ptr->' + pointer_target if is_pointer else ''}"
562564
f" ({elapsed:.3f}s)"
563565
)
@@ -568,6 +570,8 @@ def _lookup_symbol_impl(self, sym_name: str) -> Optional[dict]:
568570
"type": sym_type,
569571
"section": section,
570572
}
573+
if c_type:
574+
result["c_type"] = c_type
571575
if is_pointer:
572576
result["is_pointer"] = True
573577
result["pointer_target"] = pointer_target

Tools/WebServer/static/js/features/symbols.js

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,12 @@ function _renderSymbolValueContent(data, isConst) {
171171
: t('symbols.read_write', 'Read-Write');
172172
const isBss = data.section && data.section.startsWith('.bss');
173173

174-
// For pointer types, show the pointer type in the header
174+
// Show C type in the header (from GDB whatis)
175175
const typeDisplay = data.is_pointer
176176
? `${_escapeHtml(data.pointer_target || '?')} *`
177-
: '';
177+
: data.c_type
178+
? _escapeHtml(data.c_type)
179+
: '';
178180

179181
let headerHtml = `
180182
<div class="sym-viewer-header">
@@ -245,6 +247,32 @@ function _renderSymbolValueContent(data, isConst) {
245247
</div>`;
246248
}
247249

250+
// Scalar value decoded by backend (non-struct, non-pointer)
251+
// Render as a single tree node to reuse the struct tree style
252+
if (
253+
data.decoded_value !== undefined &&
254+
data.decoded_value !== null &&
255+
!data.is_pointer &&
256+
!(data.struct_layout && data.struct_layout.length > 0)
257+
) {
258+
const scalarLayout = [
259+
{
260+
name: data.name,
261+
offset: 0,
262+
size: data.size,
263+
type_name: data.c_type || '',
264+
},
265+
];
266+
const scalarGdbValues = { [data.name]: data.decoded_value };
267+
bodyHtml += _renderStructTree(
268+
scalarLayout,
269+
data.hex_data,
270+
isBss,
271+
scalarGdbValues,
272+
data.name,
273+
);
274+
}
275+
248276
// Struct tree view (for non-pointer structs, or for deref data)
249277
if (data.struct_layout && data.struct_layout.length > 0) {
250278
bodyHtml += _renderStructTree(
@@ -667,11 +695,12 @@ function _decodeFieldValue(hexData, offset, size, typeName) {
667695
for (let i = 0; i < bytes.length; i++) {
668696
val += bytes[i] * 256 ** i;
669697
}
670-
// Check for signed types
698+
// Check for signed types (handle "unsigned long", "long unsigned int", etc.)
671699
if (
672700
!typeName.startsWith('u') &&
673701
!typeName.startsWith('U') &&
674-
!typeName.includes('uint')
702+
!typeName.includes('uint') &&
703+
!typeName.includes('unsigned')
675704
) {
676705
const maxSigned = 2 ** (size * 8 - 1);
677706
if (val >= maxSigned) val -= 2 ** (size * 8);

0 commit comments

Comments
 (0)