/*
 * cmd_symbol.c - 符号查询命令模块（a 命令：打印地址 / 按地址反查符号）
 *
 *   a <name>            打印符号地址
 *   a <hex-address>     按地址反查符号（范围匹配 + 最近低地址偏移）
 *
 * 依赖 symbol_parse.c 的符号表与 DWARF 类型信息。
 */

#include "lnxall_trace.h"

/**
 * @brief 返回符号类型的可读名称
 *
 * @param[in] kind 细粒度符号类型（DWARF 解析结果）
 * @return 类型名称字符串（静态常量，不需释放）
 */
const char *sym_kind_name(symbol_kind_t kind)
{
    switch (kind) {
    case SYM_KIND_FUNC:    return "function";
    case SYM_KIND_INT:     return "scalar";
    case SYM_KIND_STRUCT:  return "struct";
    case SYM_KIND_UNION:   return "union";
    case SYM_KIND_ENUM:    return "enum";
    case SYM_KIND_ARRAY:   return "array";
    case SYM_KIND_POINTER: return "pointer";
    default:               return "unknown";
    }
}

/**
 * @brief 打印符号地址：a <name>
 *
 * @param[in] name 符号名(不含 '&')
 * @return 0 成功，-1 失败
 */
int cmd_print_addr(const char *name)
{
    symbol_t *sym = find_symbol_any(name);

    if (sym == NULL) {
        printf("Error: symbol '%s' not found\n", name);
        return -1;
    }
    printf("Address of %s: 0x%lx (%lu bytes, %s%s)\n",
           name, sym->addr, sym->size,
           (sym->type == SYM_FUNC) ? "function" : sym_kind_name(sym->kind),
           is_local_symbol(sym) ? ", debugger copy" : "");
    return 0;
}

/**
 * @brief 按地址反查全局符号：直接输入数值地址
 *
 * 先做范围匹配(addr ∈ [sym->addr, sym->addr+size))；未命中时
 * 返回最近的低地址符号及其偏移(类似 addr2line)。
 *
 * @param[in] addr 目标进程地址
 * @return 0 成功，-1 未找到
 */
int cmd_lookup_symbol_by_addr(unsigned long addr)
{
    symbol_t *hit = NULL;
    symbol_t *near = NULL;
    unsigned long near_off = 0;
    int i = 0;

    /* 主符号表 */
    for (i = 0; i < g_dbg.sym_count; i++) {
        symbol_t *s = &g_dbg.sym_table[i];
        if (s->size > 0 && addr >= s->addr && addr < s->addr + s->size) {
            hit = s;
            break;
        }
        if (addr >= s->addr) {
            unsigned long off = addr - s->addr;
            if (near == NULL || off < near_off) { near = s; near_off = off; }
        }
    }
    /* so 符号表 */
    if (hit == NULL) {
        for (i = 0; i < g_dbg.so_sym_count; i++) {
            symbol_t *s = &g_dbg.so_sym_table[i];
            if (s->size > 0 && addr >= s->addr && addr < s->addr + s->size) {
                hit = s;
                break;
            }
            if (addr >= s->addr) {
                unsigned long off = addr - s->addr;
                if (near == NULL || off < near_off) { near = s; near_off = off; }
            }
        }
    }

    if (hit != NULL) {
        printf("Symbol '%s' is at 0x%lx (%lu bytes, %s)\n",
               hit->name, hit->addr, hit->size,
               (hit->type == SYM_FUNC) ? "function" : sym_kind_name(hit->kind));
        return 0;
    }
    if (near != NULL) {
        printf("0x%lx is 0x%lx bytes into symbol '%s' (at 0x%lx, %s)\n",
               addr, near_off, near->name, near->addr,
               (near->type == SYM_FUNC) ? "function" : sym_kind_name(near->kind));
        return 0;
    }
    printf("No symbol matches address 0x%lx\n", addr);
    return -1;
}
