/*
 * cmd_d.c - d 命令模块（读取/显示目标数据）
 *
 * 命令形态：
 *   d <var>                读变量/结构体/数组（含嵌套字段 'a.b.c'、'a[2].x'）
 *   d <addr>,<len>         dump 目标内存（16 字节/行，地址+hex+ASCII）
 *   d &<var>               显示符号地址/大小/类型（实现在 cmd_symbol.c）
 *   d <func>               显示函数地址
 *   d <struct_name> <addr> 按结构体布局打印 addr 处内存（结构体名可选）
 *   d <addr>               纯地址：反查覆盖该地址的符号（结构体则按类型打印）
 *
 * 本模块包含全部 display/format 辅助函数（display_struct_var、
 * display_var_array、display_array_field、format_mem_value 等）。
 */

#include "lnxall_trace.h"

/* ========================================================================
 * Formatting helpers
 * ======================================================================== */

static void format_mem_value(unsigned char *buf, unsigned long size,
                             char *out, size_t out_sz)
{
    /* 注：buf 可能未按目标类型对齐（ARMv7 上未对齐 64 位访问会异常），
     * 一律 memcpy 到局部变量后读取，避免强转指针解引用。 */
    if (size == 1) {
        snprintf(out, out_sz, "%d (0x%02x)", buf[0], buf[0]);
    } else if (size == 2) {
        unsigned short vs;
        memcpy(&vs, buf, 2);
        snprintf(out, out_sz, "%d (0x%04x)", vs, vs);
    } else if (size == 4) {
        unsigned int vi;
        float vf;
        memcpy(&vi, buf, 4);
        memcpy(&vf, buf, 4);
        char hexpart[32];
        snprintf(hexpart, sizeof(hexpart), "0x%08x", vi);
        if (vi == 0) {
            snprintf(out, out_sz, "0 (%s)", hexpart);
        } else {
            /* heuristic float detection */
            if (vi != 0 && vi < 0x80000000u) {
                snprintf(out, out_sz, "%d  float: %f (%s)",
                         (int)vi, (double)vf, hexpart);
            } else {
                snprintf(out, out_sz, "%u (%s)", vi, hexpart);
            }
        }
    } else if (size == 8) {
        unsigned long long vl;
        double vd;
        memcpy(&vl, buf, 8);
        memcpy(&vd, buf, 8);
        if (vl == 0) {
            snprintf(out, out_sz, "0 (0x%016llx)", vl);
        } else {
            snprintf(out, out_sz, "%lld  double: %f (0x%016llx)",
                     (long long)vl, vd, vl);
        }
    } else {
        /* larger: hex dump first 16 bytes */
        size_t n = size < 16 ? size : 16;
        out[0] = '\0';
        int pos = 0;
        for (size_t i = 0; i < n && pos < (int)out_sz - 3; i++) {
            pos += snprintf(out + pos, out_sz - pos, "%02x ", buf[i]);
        }
        if (size > 16) snprintf(out + pos, out_sz - pos, "...");
    }
}

/* Find field by name in a given struct */
static struct_field_t *find_field_in_struct(struct_info_t *si,
                                             const char *field_name)
{
    if (!si) return NULL;
    for (int i = 0; i < si->field_count; i++) {
        if (strcmp(si->fields[i].name, field_name) == 0)
            return &si->fields[i];
    }
    return NULL;
}

/* 尝试把 addr 处 count 字节读为 C 字符串。
 * 全部字节为可打印 ASCII 或 '\0' 时返回 0 并填充 out（到首个 '\0' 为止）；
 * 含控制/二进制字节、或读取失败时返回 -1（调用方回退到逐元素打印）。 */
int read_printable_string(unsigned long addr, unsigned long count,
                          char *out, size_t out_sz)
{
    unsigned char tmp[512];
    size_t n = count > sizeof(tmp) ? sizeof(tmp) : count;
    if (n == 0) return -1;
    if (read_any_mem(addr, tmp, n) != 0) return -1;
    size_t len = 0;
    for (size_t i = 0; i < n; i++) {
        unsigned char c = tmp[i];
        if (c == '\0') break;                    /* 字符串在此结束 */
        if (c < 0x20 || c > 0x7e) return -1;     /* 含非文本字节 → 非字符串 */
        if (len < out_sz - 1) out[len++] = (char)c;
    }
    out[len] = '\0';
    return 0;
}

/* Display a single array member as an element overview.
 * Used for 'd var.arrfield' without an index.
 * char 数组（元素 1 字节且内容可打印）直接按字符串显示。 */
int display_array_field(const char *var_name, unsigned long base,
                        struct_field_t *f)
{
    if (f->arr_elem_size == 1) {
        char sbuf[512];
        if (read_printable_string(base + f->offset, f->arr_count,
                                  sbuf, sizeof(sbuf)) == 0) {
            printf("  .%-40s  off=%-4lu  size=%-4lu  = \"%s\" (len=%lu)\n",
                   f->name, f->offset, f->size, sbuf,
                   (unsigned long)strlen(sbuf));
            return 0;
        }
        /* 含二进制内容 → 回退到逐元素打印 */
    }
    printf("  .%-40s  off=%-4lu  size=%-4lu  array[%lu] of %luB:\n",
           f->name, f->offset, f->size, f->arr_count, f->arr_elem_size);
    unsigned long shown = f->arr_count;
    if (shown > 16) shown = 16;
    unsigned char ebuf[16];
    /* element struct name (if resolvable) for a nicer hint */
    struct_info_t *es = NULL;
    {
        unsigned long er = resolve_array_elem_ref_rt(f->type_ref);
        if (er) es = find_struct_by_die_offset(resolve_typedef_chain_rt(er));
    }
    for (unsigned long e = 0; e < shown; e++) {
        if (f->arr_elem_size > 8) {
            /* element is a struct / opaque blob: don't dump raw bytes,
             * tell the user how to index into it */
            printf("      [%lu] = struct %s (%luB) — use  d %s.%s[%lu].<field>\n",
                   e, es ? (es->name[0] ? es->name : "<anonymous>") : "opaque",
                   f->arr_elem_size, var_name, f->name, e);
            continue;
        }
        if (read_any_mem(base + f->offset + e * f->arr_elem_size,
                         ebuf, f->arr_elem_size) != 0) break;
        char vstr[256];
        format_mem_value(ebuf, f->arr_elem_size, vstr, sizeof(vstr));
        printf("      [%lu] = %s\n", e, vstr);
    }
    if (f->arr_count > shown)
        printf("      ... (%lu more elements)\n", f->arr_count - shown);
    return 0;
}

/* Format one array element for display.  8-byte elements (e.g. pointer
 * arrays like 'const char *show_log[]') are shown as a pointer value with
 * a best-effort string dereference when the target is readable printable
 * text; otherwise fall back to the generic value formatter. */
static void format_array_element_val(pid_t pid, unsigned long elem_addr,
                                     unsigned long elem_size,
                                     char *out, size_t out_sz)
{
    unsigned char buf[64];
    size_t rsize = elem_size < sizeof(buf) ? elem_size : sizeof(buf);
    if (mem_read(pid, elem_addr, buf, rsize) != 0) {
        snprintf(out, out_sz, "<read error>");
        return;
    }
    if (elem_size == 8) {
        unsigned long long ptr;
        memcpy(&ptr, buf, 8);
        if (ptr >= 0x1000) {   /* plausibly a valid address, not a small int */
            char sbuf[40];
            if (mem_read(pid, (unsigned long)ptr, (unsigned char *)sbuf,
                         sizeof(sbuf) - 1) == 0) {
                sbuf[sizeof(sbuf) - 1] = '\0';
                int printable = 1;
                for (size_t i = 0; sbuf[i] && i < sizeof(sbuf) - 1; i++) {
                    unsigned char c = (unsigned char)sbuf[i];
                    if (c < 0x20 && c != '\t' && c != '\n' && c != '\r') {
                        printable = 0;
                        break;
                    }
                }
                if (printable && sbuf[0]) {
                    snprintf(out, out_sz, "0x%llx \"%s\"", ptr, sbuf);
                    return;
                }
            }
        }
    }
    format_mem_value(buf, elem_size, out, out_sz);
}

/* Display a top-level variable that is itself an array type
 * ('d varname' for a struct-array / base-array global).
 * elem_struct != NULL → elements are structs: print usage hint only;
 * otherwise read each element and format it as a plain value. */
int display_var_array(const char *var_name, unsigned long addr,
                      unsigned long elem_count, unsigned long elem_size,
                      struct_info_t *elem_struct)
{
    unsigned long total = elem_count * elem_size;
    /* char 数组：内容可打印时直接按字符串显示 */
    if (elem_size == 1 && elem_struct == NULL) {
        char sbuf[512];
        if (read_printable_string(addr, elem_count, sbuf, sizeof(sbuf)) == 0) {
            printf("%s  (addr=0x%lx, %lu bytes) = \"%s\" (len=%lu)\n",
                   var_name, addr, total, sbuf, (unsigned long)strlen(sbuf));
            return 0;
        }
    }
    printf("%s  (addr=0x%lx, %lu bytes, array[%lu] of %s%luB):\n",
           var_name, addr, total, elem_count,
           elem_struct ? "struct " : "", elem_size);
    if (elem_count == 0 || elem_size == 0) return 0;

    unsigned long shown = elem_count > 16 ? 16 : elem_count;
    for (unsigned long e = 0; e < shown; e++) {
        if (elem_struct) {
            printf("      [%lu] = struct %s (%luB) — use  d %s[%lu].<field>\n",
                   e, elem_struct->name[0] ? elem_struct->name : "<anonymous>",
                   elem_size, var_name, e);
            continue;
        }
        char vstr[256];
        format_array_element_val(g_dbg.target_pid, addr + e * elem_size,
                                 elem_size, vstr, sizeof(vstr));
        printf("      [%lu] = %s\n", e, vstr);
    }
    if (elem_count > shown)
        printf("      ... (%lu more elements)\n", elem_count - shown);
    return 0;
}

/* Display an entire struct by reading process memory.
 * 'si' is the DWARF-resolved struct type (never NULL when called). */
int display_struct_var(const char *var_name,
                       unsigned long addr, unsigned long size,
                       struct_info_t *si)
{
    printf("%s  (addr=0x%lx, %lu bytes, struct %s):\n",
           var_name, addr, size, si->name[0] ? si->name : "<anonymous>");

    for (int i = 0; i < si->field_count; i++) {
        struct_field_t *f = &si->fields[i];
        if (f->size == 0)
            DBG("display_struct_var: field '%s.%s' has size=0, skipping",
                si->name, f->name);
        if (f->offset + f->size > size) continue;   /* safety check */

        /* array member: print elements individually */
        if (f->arr_count > 1 && f->arr_elem_size > 0) {
            display_array_field(var_name, addr, f);
            continue;
        }

        unsigned char buf[128];
        size_t read_sz = f->size < sizeof(buf) ? f->size : sizeof(buf);
        if (read_any_mem(addr + f->offset, buf, read_sz) != 0) break;

        char valstr[256];
        format_mem_value(buf, f->size, valstr, sizeof(valstr));

        printf("  .%-40s  off=%-4lu  size=%-4lu  = %s\n",
               f->name, f->offset, f->size, valstr);
    }
    return 0;
}

/* Split a path token of the form 'name' or 'name[idx]' into the plain
 * field name and a numeric index.  *idx is -1 when there is no '[..]'. */
static void parse_field_token(const char *tok, char *name, size_t name_sz,
                              long *idx)
{
    const char *lb = strchr(tok, '[');
    size_t n = lb ? (size_t)(lb - tok) : strlen(tok);
    if (n >= name_sz) n = name_sz - 1;
    memcpy(name, tok, n);
    name[n] = '\0';
    *idx = -1;
    if (lb) {
        const char *c = lb + 1;
        char num[20];
        int k = 0;
        while (*c >= '0' && *c <= '9' && k < (int)sizeof(num) - 1)
            num[k++] = *c++;
        num[k] = '\0';
        if (k > 0 && *c == ']')
            *idx = atol(num);
    }
}

/* Resolve 'base_var.field1[.field2...]' to final address & size.
 * Returns 0 on success with *out_addr and *out_size set.
 * If *out_si is non-NULL and the final target is a struct (or a
 * struct-typed array element), *out_si is set to its definition.
 * *out_last_f / *out_last_idx receive the final token's field and index
 * (used by the caller to detect a whole-array access). */
int resolve_struct_field_path(const char *var_name,
                              unsigned long *out_addr,
                              unsigned long *out_size,
                              char **dot_pos_out,
                              struct_info_t **out_si,
                              struct_field_t **out_last_f,
                              long *out_last_idx,
                              symbol_t **out_base_sym)
{
    /* 1. Split into base var + field path */
    char vn[MAX_NAME_LEN];
    safe_strcpy(vn, var_name, MAX_NAME_LEN);

    char *dot = strchr(vn, '.');
    if (!dot) return -1;

    *dot = '\0';
    char *field_path = dot + 1;
    if (dot_pos_out) *dot_pos_out = dot;

    /* 2. Find base variable; may be 'name' or 'name[idx]' (array element) */
    char base_name[MAX_NAME_LEN];
    safe_strcpy(base_name, vn, MAX_NAME_LEN);
    long base_idx = -1;
    char *lb = strchr(base_name, '[');
    if (lb) {
        *lb = '\0';
        base_idx = strtol(lb + 1, NULL, 10);
    }

    symbol_t *sym = NULL;
    for (int i = 0; i < g_dbg.sym_count; i++) {
        if (strcmp(g_dbg.sym_table[i].name, base_name) == 0) {
            sym = &g_dbg.sym_table[i];
            break;
        }
    }
    /* local (out-param scratch) struct copies can anchor a field path too */
    if (!sym) {
        for (int i = 0; i < g_dbg.local_sym_count; i++) {
            if (strcmp(g_dbg.local_sym_table[i].name, base_name) == 0) {
                sym = &g_dbg.local_sym_table[i];
                break;
            }
        }
    }
    if (!sym || sym->type == SYM_FUNC) {
        printf("Error: variable '%s' not found\n", base_name);
        return -1;
    }

    /* use DWARF-precise struct match, fallback to size-based */
    struct_info_t *si = NULL;
    if (sym->kind == SYM_KIND_ARRAY && sym->struct_idx >= 0 &&
        sym->struct_idx < g_dbg.struct_count) {
        /* base is a struct-array variable: anchor on the element struct */
        si = &g_dbg.structs[sym->struct_idx];
    } else if (sym->kind == SYM_KIND_STRUCT && sym->struct_idx >= 0 &&
        sym->struct_idx < g_dbg.struct_count) {
        si = &g_dbg.structs[sym->struct_idx];
    } else {
        si = find_struct_by_size(sym->size);
    }
    if (!si) {
        printf("Error: no struct info for '%s' (size=%lu)\n",
               base_name, sym->size);
        return -1;
    }

    unsigned long cur_addr = sym->addr;
    unsigned long cur_size = sym->size;
    if (base_idx >= 0) {
        /* index into the top-level array variable */
        unsigned long bcnt = 0, besize = 0;
        struct_info_t *bes = NULL;
        if (sym->kind == SYM_KIND_ARRAY &&
            resolve_var_array_rt(sym, &bcnt, &besize, &bes) == 0 &&
            bcnt > 0 && besize > 0) {
            if ((unsigned long)base_idx >= bcnt) {
                printf("Error: index %ld out of range [0..%lu) for '%s'\n",
                       base_idx, bcnt, base_name);
                return -1;
            }
            cur_addr += (unsigned long)base_idx * besize;
            cur_size  = besize;
        } else {
            printf("Error: '%s' is not an array variable\n", base_name);
            return -1;
        }
    }

    char *saveptr;
    char *token = strtok_r(field_path, ".", &saveptr);
    struct_field_t *last_f = NULL;   /* final token's field (for out_si) */
    long             last_idx = -1;
    while (token) {
        char fname[MAX_FIELD_NAME_LEN];
        long idx;
        parse_field_token(token, fname, sizeof(fname), &idx);

        struct_field_t *f = find_field_in_struct(si, fname);
        if (!f) {
            printf("Error: field '%s' not found in struct '%s'\n",
                   fname, si->name[0] ? si->name : "<anonymous>");
            return -1;
        }
        last_f   = f;
        last_idx = idx;

        unsigned long f_off = f->offset;
        unsigned long f_sz  = f->size;
        if (idx >= 0) {
            /* indexed access into an array member */
            if (f->arr_count == 0 || f->arr_elem_size == 0) {
                printf("Error: field '%s' is not an array\n", fname);
                return -1;
            }
            if ((unsigned long)idx >= f->arr_count) {
                printf("Error: index %ld out of range [0..%lu) for '%s'\n",
                       idx, f->arr_count, fname);
                return -1;
            }
            f_off += (unsigned long)idx * f->arr_elem_size;
            f_sz   = f->arr_elem_size;
        }
        cur_addr += f_off;
        cur_size = f_sz;

        token = strtok_r(NULL, ".", &saveptr);
        if (token) {
            /* need next-level struct */
            if (cur_size == 0)
                DBG("resolve_field: field '%s' size=0, nested lookup may fail", fname);
            si = find_struct_by_size(cur_size);
            if (!si) {
                printf("Error: no struct info for field '%s' (size=%lu)\n",
                       fname, cur_size);
                return -1;
            }
        }
    }

    /* Determine the final target's struct type (if any) */
    if (out_si) {
        *out_si = NULL;
        if (last_f) {
            unsigned long target = (last_idx >= 0)
                ? resolve_array_elem_ref_rt(last_f->type_ref)
                : last_f->type_ref;
            if (target) {
                target = resolve_typedef_chain_rt(target);
                *out_si = find_struct_by_die_offset(target);
            }
            /* fallback: unambiguous size-based struct match */
            if (!*out_si && cur_size > 0) {
                struct_info_t *s = find_struct_by_size(cur_size);
                if (s && s->size == cur_size)
                    *out_si = s;
            }
        }
    }

    if (out_last_f)   *out_last_f   = last_f;
    if (out_last_idx) *out_last_idx = last_idx;

    *out_addr = cur_addr;
    *out_size = cur_size;
    if (out_base_sym) *out_base_sym = sym;
    return 0;
}

/* ========================================================================
 * d <addr>,<len> — dump target memory (16 bytes per line)
 * ======================================================================== */

int cmd_dump_memory(const char *spec)
{
    unsigned long addr = 0;
    unsigned long len  = 0;
    char *ep = NULL;

    if (!g_dbg.is_attached) {
        printf("Error: Not attached.\n");
        return -1;
    }
    addr = strtoul(spec, &ep, 0);
    if (ep == spec || *ep != ',') {
        printf("Usage: d <addr>,<len>   (e.g. d 0x40a000,64)\n");
        return -1;
    }
    len = strtoul(ep + 1, &ep, 0);
    if (*ep != '\0' || len == 0) {
        printf("Usage: d <addr>,<len>   (e.g. d 0x40a000,64)\n");
        return -1;
    }
    if (len > MAX_MEM_OPS_SIZE) {
        printf("Error: len %lu exceeds max dump size %d\n", len, MAX_MEM_OPS_SIZE);
        return -1;
    }

    if (target_freeze() != 0) return -1;

    unsigned char *buf = malloc(len);
    if (buf == NULL) {
        target_thaw();
        printf("Error: out of memory (%lu bytes)\n", len);
        return -1;
    }
    int rc = mem_read(g_dbg.target_pid, addr, buf, len);
    if (rc != 0) {
        printf("Error: cannot read target memory at 0x%lx\n", addr);
    } else {
        printf("Memory dump 0x%lx .. 0x%lx (%lu bytes):\n",
               addr, addr + len - 1, len);
        for (unsigned long i = 0; i < len; i += MEM_DUMP_LINE_BYTES) {
            size_t n = len - i;
            if (n > MEM_DUMP_LINE_BYTES) n = MEM_DUMP_LINE_BYTES;
            printf("  0x%016lx: ", addr + i);
            for (size_t j = 0; j < MEM_DUMP_LINE_BYTES; j++) {
                if (j < n) printf("%02x ", buf[i + j]);
                else       printf("   ");
                if (j == 7) printf(" ");
            }
            printf(" |");
            for (size_t j = 0; j < n; j++) {
                unsigned char c = buf[i + j];
                printf("%c", (c >= 0x20 && c < 0x7f) ? (char)c : '.');
            }
            printf("|\n");
        }
    }
    free(buf);
    target_thaw();
    return rc;
}

/* 前置声明：地址反查命中非结构体符号时按类型分发显示
 * （完整实现位于本文件下方 display_var_* 区）。 */
static int display_var_array_obj(const char *var_name, const symbol_t *sym);
static int display_var_plain_value(const char *var_name, const symbol_t *sym);

/* d <struct_name> <addr> — 把 <addr> 处的目标内存按结构体 <struct_name>
 * 的布局打印（结构体名是可选参数）。未指定结构体名时，按地址反查符号，
 * 命中结构体符号按其类型打印，命中数组/标量/函数符号按各自方式显示。 */
int cmd_print_struct_ptr(const char *struct_name, const char *addr_spec)
{
    if (!g_dbg.is_attached) {
        printf("Error: Not attached.\n"); return -1;
    }

    unsigned long addr;
    if (parse_int_value(addr_spec, &addr) != 0) {
        printf("Error: Invalid address '%s'\n", addr_spec);
        return -1;
    }

    struct_info_t *si = NULL;

    if (struct_name != NULL && *struct_name != '\0') {
        for (int i = 0; i < g_dbg.struct_count; i++) {
            if (strcasecmp(g_dbg.structs[i].name, struct_name) == 0) {
                si = &g_dbg.structs[i];
                break;
            }
        }
        if (si == NULL) {
            printf("Error: struct type '%s' not found (use 'ptype' to list)\n",
                   struct_name);
            return -1;
        }
    } else {
        /* 未指定结构体名：按地址反查符号。
         * 命中条件：addr 落在符号区间 [addr, addr+size)（size 为 0 的
         * 符号（如函数）退化为 addr == s->addr 精确命中）。 */
        symbol_t *hit = NULL;
        for (int i = 0; i < g_dbg.sym_count; i++) {
            symbol_t *s = &g_dbg.sym_table[i];
            if (addr >= s->addr &&
                addr < s->addr + (s->size > 0 ? s->size : 1)) {
                hit = s; break;
            }
        }
        if (hit == NULL) {
            for (int i = 0; i < g_dbg.so_sym_count; i++) {
                symbol_t *s = &g_dbg.so_sym_table[i];
                if (addr >= s->addr &&
                    addr < s->addr + (s->size > 0 ? s->size : 1)) {
                    hit = s; break;
                }
            }
        }
        if (hit == NULL) {
            printf("Error: 0x%lx does not map to any known symbol.\n"
                   "  Usage: d <struct_name> <addr>   or   d <addr>,<len>\n",
                   addr);
            /* 排查提示：给出地址最近的符号，便于定位 PIE 基址未换算 /
             * 符号未加载等问题 */
            symbol_t *nearest = NULL;
            unsigned long ndist = 0, first = 1;
            for (int i = 0; i < g_dbg.sym_count; i++) {
                symbol_t *s = &g_dbg.sym_table[i];
                if (s->size == 0) continue;
                unsigned long d = (addr >= s->addr) ?
                                  (addr - s->addr) : (s->addr - addr);
                if (first || d < ndist) { ndist = d; nearest = s; first = 0; }
            }
            if (nearest != NULL)
                printf("  nearest symbol: %s @ 0x%lx (size %lu, %s)\n",
                       nearest->name, nearest->addr, nearest->size,
                       sym_kind_name(nearest->kind));
            return -1;
        }
        /* 命中符号：按 DWARF 类型分发显示 */
        switch (hit->kind) {
        case SYM_KIND_STRUCT:
        case SYM_KIND_UNION:
            if (hit->struct_idx < 0 || hit->struct_idx >= g_dbg.struct_count) {
                printf("Error: symbol '%s' at 0x%lx has no resolvable "
                       "struct layout.\n", hit->name, addr);
                return -1;
            }
            si = &g_dbg.structs[hit->struct_idx];
            struct_name = hit->name;
            break;
        case SYM_KIND_ARRAY:
            return display_var_array_obj(hit->name, hit);
        case SYM_KIND_FUNC:
            printf("%s  @ 0x%lx  (function, %lu bytes)\n",
                   hit->name, addr, hit->size);
            return 0;
        default:
            return display_var_plain_value(hit->name, hit);
        }
    }

    char dname[160];
    snprintf(dname, sizeof(dname), "struct %s @ 0x%lx",
             si->name[0] ? si->name : struct_name, addr);

    if (target_freeze() != 0) return -1;
    int ret = display_struct_var(dname, addr, si->size, si);
    target_thaw();
    return ret;
}

/* ========================================================================
 * d <var> — read variable / struct / array
 * ======================================================================== */

/**
 * @brief 显示按 DWARF 确认的结构体变量（含调试器本地副本路径）
 *
 * @param[in] var_name 变量名（用于标题显示）
 * @param[in] sym      已确认类型为结构体的符号
 * @return 0 成功，-1 失败
 */
static int display_var_struct(const char *var_name, const symbol_t *sym)
{
    struct_info_t *si = &g_dbg.structs[sym->struct_idx];
    DBG("cmd_read_var: '%s' kind=struct[%d] '%s', field_count=%d → "
        "using struct display",
        var_name, sym->struct_idx, si->name, si->field_count);
    if (is_local_symbol(sym)) {
        /* debugger-side out-param struct copy: no ptrace interaction */
        return display_struct_var(var_name, sym->addr, sym->size, si);
    }
    if (target_freeze() != 0) return -1;
    int ret = display_struct_var(var_name, sym->addr, sym->size, si);
    target_thaw();
    return ret;
}

/**
 * @brief 显示顶层数组变量的元素概览
 *
 * 数组形状无法解析时返回 -1，由调用方回退到普通值显示。
 *
 * @param[in] var_name 变量名（用于标题显示）
 * @param[in] sym      类型为数组的符号
 * @return 0 成功，-1 形状未解析/失败
 */
static int display_var_array_obj(const char *var_name, const symbol_t *sym)
{
    unsigned long bcnt = 0, besize = 0;
    struct_info_t *bes = NULL;
    if (resolve_var_array_rt(sym, &bcnt, &besize, &bes) != 0 ||
        bcnt == 0 || besize == 0)
        return -1;   /* 形状未解析：回退普通显示 */
    DBG("cmd_read_var: '%s' kind=array[%lu] of %luB%s → "
        "using array overview",
        var_name, bcnt, besize, bes != NULL ? " struct" : "");
    if (target_freeze() != 0) return -1;
    int ret = display_var_array(var_name, sym->addr, bcnt, besize, bes);
    target_thaw();
    return ret;
}

/**
 * @brief 显示普通变量值（标量/未知类型/未解析形状的数组）
 *
 * 调试器本地副本直接读本进程堆；目标变量需暂停目标后经 ptrace 读取。
 *
 * @param[in] var_name 变量名（用于标题显示）
 * @param[in] sym      目标符号
 * @return 0 成功，-1 失败
 */
static int display_var_plain_value(const char *var_name, const symbol_t *sym)
{
    unsigned long value = 0;
    char raw[256] = {0};
    size_t rsize = (sym->size < 256) ? sym->size : 255;
    int is_local = is_local_symbol(sym);

    if (is_local) {
        /* Debugger-side out-param copy: the value lives in our heap, not
         * in the target, so no thread stop / ptrace is required. */
        memcpy(raw, (const void *)sym->addr, rsize);
    } else {
        if (target_read_mem(sym->addr, raw, rsize) != 0) return -1;
    }
    memcpy(&value, raw, sizeof(value) < rsize ? sizeof(value) : rsize);

    if (sym->kind == SYM_KIND_UNKNOWN) {
        /* 维测: distinguish "no DWARF record" from "DWARF type unresolved" */
        printf("%s  (0x%lx, %lu bytes, %s%s)  [diag: %s] = ",
               var_name, sym->addr, sym->size, sym_kind_name(sym->kind),
               is_local ? ", debugger copy" : "",
               sym->has_dwarf ? "DWARF type unresolved"
                              : "no DWARF record for this symbol");
    } else {
        printf("%s  (0x%lx, %lu bytes, %s%s) = ",
               var_name, sym->addr, sym->size, sym_kind_name(sym->kind),
               is_local ? ", debugger copy" : "");
    }
    if      (sym->size == 1)
        printf("%d / 0x%02lx\n", (int)(value & 0xFF), value & 0xFF);
    else if (sym->size == 2)
        printf("%d / 0x%04lx\n", (short)(value & 0xFFFF), value & 0xFFFF);
    else if (sym->size == 4) {
        unsigned int iv; float fv;
        memcpy(&iv, raw, 4);
        memcpy(&fv, raw, 4);
        printf("int: %d (0x%08x)  |  float: %f\n",
               (int)iv, iv, (double)fv);
    }
    else if (sym->size == 8) {
        /* 须用 8 字节整型承载：ARM32(ILP32) 下 unsigned long 仅 4 字节，
         * memcpy 8 字节会越界写坏栈上相邻局部变量，且只显示低 32 位。 */
        unsigned long long lv; double dv;
        memcpy(&lv, raw, 8);
        memcpy(&dv, raw, 8);
        printf("long: %lld (0x%016llx)  |  double: %.10g\n",
               (long long)lv, lv, dv);
    }
    else {
        printf("[%lu bytes]\n", sym->size);
        printf("  hex: ");
        for (size_t j = 0; j < sym->size && j < 32; j++)
            printf("%02x ", (unsigned char)raw[j]);
        printf("\n");
    }
    return 0;
}

/**
 * @brief 读取 'struct.field' 路径变量
 *
 * 基础符号为调试器本地副本时直接在调试器堆解析读取；
 * 否则暂停目标后经 ptrace 读取，支持嵌套结构体与数组字段展开。
 *
 * @param[in] var_name 含 '.' 的变量路径
 * @return 0 成功，-1 失败
 */
static int read_var_field_path(const char *var_name)
{
    unsigned long faddr = 0, fsize = 0;
    struct_info_t *tgt_si = NULL;
    struct_field_t *last_f = NULL;
    long            last_idx = -1;
    symbol_t *base_sym = NULL;
    if (resolve_struct_field_path(var_name, &faddr, &fsize, NULL,
                                  &tgt_si, &last_f, &last_idx,
                                  &base_sym) != 0)
        return -1;

    if (base_sym != NULL && is_local_symbol(base_sym)) {
        /* debugger-side out-param copy: resolve & read entirely in our
         * heap, no ptrace interaction with the target needed */
        if (tgt_si != NULL)
            return display_struct_var(var_name, faddr, fsize, tgt_si);
        if (last_f != NULL && last_idx < 0 && last_f->arr_count > 1 &&
            last_f->arr_elem_size > 0)
            return display_array_field(var_name, faddr, last_f);
        unsigned char buf[128];
        size_t rsize = fsize < sizeof(buf) ? fsize : sizeof(buf);
        if (read_any_mem(faddr, buf, rsize) != 0) return -1;
        char valstr[256];
        format_mem_value(buf, fsize, valstr, sizeof(valstr));
        printf("%s  (addr=0x%lx, %lu bytes, debugger copy) = %s\n",
               var_name, faddr, fsize, valstr);
        return 0;
    }

    if (target_freeze() != 0) return -1;

    /* nested struct or array element of struct → expand fields */
    if (tgt_si != NULL) {
        DBG("cmd_read_var: '%s' → struct '%s' (%luB), expanding fields",
            var_name, tgt_si->name[0] ? tgt_si->name : "<anonymous>", fsize);
        int ret = display_struct_var(var_name, faddr, fsize, tgt_si);
        target_thaw();
        return ret;
    }

    /* whole array member without index → element overview */
    if (last_f != NULL && last_idx < 0 && last_f->arr_count > 1 &&
        last_f->arr_elem_size > 0) {
        int ret = display_array_field(var_name, faddr, last_f);
        target_thaw();
        return ret;
    }

    unsigned char buf[128];
    size_t rsize = fsize < sizeof(buf) ? fsize : sizeof(buf);
    if (mem_read(g_dbg.target_pid, faddr, buf, rsize) != 0) {
        target_thaw(); return -1;
    }
    target_thaw();

    char valstr[256];
    format_mem_value(buf, fsize, valstr, sizeof(valstr));
    printf("%s  (addr=0x%lx, %lu bytes) = %s\n",
           var_name, faddr, fsize, valstr);
    return 0;
}

/**
 * @brief 读取顶层数组索引访问 'name[idx]'
 *
 * 仅处理可解析为数组下标的形式；解析失败返回 -1，由调用方
 * 回退到常规符号查找（负责报告最终错误）。
 *
 * @param[in] var_name 含 '[' 的变量名
 * @return 0 成功，-1 非数组访问/下标越界/解析失败
 */
static int read_var_array_index(const char *var_name)
{
    char base_name[MAX_NAME_LEN];
    safe_strcpy(base_name, var_name, MAX_NAME_LEN);
    char *lb = strchr(base_name, '[');
    if (lb == NULL)
        return -1;
    *lb = '\0';
    symbol_t *asym = find_symbol(base_name, SYM_OBJECT);
    if (asym == NULL || asym->kind != SYM_KIND_ARRAY)
        return -1;

    long idx = strtol(lb + 1, NULL, 10);
    unsigned long bcnt = 0, besize = 0;
    struct_info_t *bes = NULL;
    if (resolve_var_array_rt(asym, &bcnt, &besize, &bes) != 0 ||
        bcnt == 0 || besize == 0)
        return -1;
    if (idx < 0 || (unsigned long)idx >= bcnt) {
        printf("Error: index %ld out of range [0..%lu) for '%s'\n",
               idx, bcnt, base_name);
        return -1;
    }

    unsigned long eaddr = asym->addr + (unsigned long)idx * besize;
    if (target_freeze() != 0) return -1;
    int ret;
    if (bes != NULL) {
        ret = display_struct_var(var_name, eaddr, besize, bes);
    } else {
        char vstr[256];
        format_array_element_val(g_dbg.target_pid, eaddr,
                                 besize, vstr, sizeof(vstr));
        printf("%s  (addr=0x%lx, %lu bytes) = %s\n",
               var_name, eaddr, besize, vstr);
        ret = 0;
    }
    target_thaw();
    return ret;
}

/**
 * @brief 读取常规变量（非 '.'/非可解析 '[' 路径）
 *
 * 负责符号查找与类型分派：函数地址提示、结构体/数组/普通值显示。
 *
 * @param[in] var_name 变量名
 * @return 0 成功，-1 失败
 */
static int read_var_plain(const char *var_name)
{
    symbol_t *sym = find_symbol(var_name, SYM_OBJECT);
    if (sym == NULL) {
        sym = find_symbol_any(var_name);
        if (sym != NULL && sym->type == SYM_FUNC) {
            /* d <func_name> — show function address */
            printf("Address of function '%s': 0x%lx\n", var_name, sym->addr);
            return 0;
        }
        if (sym != NULL && sym->type != SYM_OBJECT) {
            printf("Error: '%s' is a %s, not a variable\n",
                   var_name, sym->type == SYM_FUNC ? "function" : "symbol");
            return -1;
        }
        printf("Error: Variable '%s' not found in symbols\n", var_name);
        return -1;
    }

    DBG("cmd_read_var: '%s' found, addr=0x%lx, size=%lu, type=%d",
        var_name, sym->addr, sym->size, sym->type);

    /* Try struct display for variables confirmed as struct by DWARF type info */
    if (sym->kind == SYM_KIND_STRUCT && sym->struct_idx >= 0 &&
        sym->struct_idx < g_dbg.struct_count)
        return display_var_struct(var_name, sym);

    /* Top-level array variable (e.g. a struct-array global) → element overview */
    if (sym->kind == SYM_KIND_ARRAY && display_var_array_obj(var_name, sym) == 0)
        return 0;   /* 形状未解析时回退到普通值显示 */

    DBG("cmd_read_var: '%s' kind=%d → using plain display", var_name, sym->kind);
    return display_var_plain_value(var_name, sym);
}

int cmd_read_var(const char *var_name)
{
    if (!g_dbg.is_attached) {
        printf("Error: Not attached.\n"); return -1;
    }

    /* --- struct.field 访问 --- */
    if (strchr(var_name, '.'))
        return read_var_field_path(var_name);

    /* --- 顶层数组索引 'name[idx]'（解析失败落到常规查找报告错误） --- */
    if (strchr(var_name, '[') && read_var_array_index(var_name) == 0)
        return 0;

    /* --- 常规变量读取 --- */
    return read_var_plain(var_name);
}
