/*
 * lnxall_trace.h - 公共头文件：宏、类型、全局状态与跨模块函数原型
 *
 * 由 lnxall_trace.c 按功能拆分而来（模块划分见各 .c 文件头注释）。
 * 拆分为：main(命令解析)/cmd_attach/cmd_d/cmd_m/cmd_call/cmd_so/
 *         cmd_struct/cmd_symbol/thread_ops/mem_rw/symbol_parse/dwarf_parse
 *
 * Build:  make
 * Usage:  ./lnxall_trace [<PID>]
 */

#ifndef LNXALL_TRACE_H
#define LNXALL_TRACE_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <signal.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/user.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <elf.h>
#include <ctype.h>
#include <stdint.h>
#include <dirent.h>
#include <syslog.h>
#include <sys/select.h>

/* CPU 架构移植层：寄存器访问/调用约定特征/断点指令等架构强相关定义 */
#include "arch_port.h"

/* ------------------------------------------------------------------------
 * ptrace 事件常量兼容层
 *
 * PTRACE_EVENT_STOP 由 glibc 2.26（2017 年）才引入；较旧工具链（如部分
 * ARMv7 交叉编译环境）的 <sys/ptrace.h> 缺失该宏。其内核 ABI 值 128
 * （0x80，asm/ptrace.h 定义）稳定不变，此处按规范提供 fallback。
 * ------------------------------------------------------------------------ */
#ifndef PTRACE_EVENT_STOP
#define PTRACE_EVENT_STOP 128
#endif

/* ========================================================================
 * Constants & Macros
 * ======================================================================== */

#define MAX_SYMBOLS         8192
#define MAX_CHILDREN        256
#define MAX_CMD_LEN         1024
#define MAX_NAME_LEN        256
#define MAX_STR_ARG         512
#define MAX_FUNC_ARGS       ARCH_MAX_CALL_ARGS /* 单次 call 参数上限：寄存器参数
                                   + AAPCS 栈参数区，随架构变化（ARM32=8） */
#define MAX_THREADS         256
#define MAX_LOCAL_SYMS      256     /* '<type> <name> = <val>' out-param scratch symbols
                                       (debugger-side heap copies) */

/* NOTE: the injected-call path uses NO built-in timeout, mirroring gdb on
 * native (sync) targets (`set direct-call-timeout unlimited' default):
 * the call runs until it returns, faults, the target exits, or the user
 * presses Ctrl-C (g_intr_requested), which interrupts the target and
 * leaves it stopped inside the callee frame. */
#define MAX_STRUCT_FIELDS   128
#define STRUCT_FIELDS_INIT  8       /* fields 初始容量（按需倍增增长，上限 MAX_STRUCT_FIELDS） */
#define STRUCTS_INIT_CAP    1024    /* 结构体表初始容量（按需倍增扩容） */
#define MAX_STRUCTS         65536   /* 结构体表硬上限（防无限增长，与 so 表一致） */
#define WORD_SIZE           sizeof(long)
#define MAX_MEM_OPS_SIZE   4096    /* 'd <addr>,<len>' / 'm <addr>,<len>' 单次内存操作最大字节数 */
#define MEM_DUMP_LINE_BYTES 16     /* dump 每行显示的字节数(16 字节对齐) */
#define MAX_SO_LOADS       32      /* 'loadso' 可同时跟踪的最大 so 个数 */
#define SO_PATH_MAX        MAX_NAME_LEN
#define SO_BASE_MAX        128

/* ------------------------------------------------------------------------
 * Debug toggle:  set to 1 to enable verbose diagnostics on stderr,
 *                0 to silence them.
 * ------------------------------------------------------------------------ */
#define DEBUG 0

#define DBG(fmt, ...) do { \
    if (DEBUG || g_dbg.verbose) fprintf(stderr, "[DBG] " fmt "\n", ##__VA_ARGS__); \
} while (0)

/* ========================================================================
 * Data Structures
 * ======================================================================== */

typedef enum {
    SYM_OBJECT = 0,
    SYM_FUNC   = 1
} sym_type_t;

/* fine-grained symbol kind, filled by the DWARF type resolver.
 * UNKNOWN = ELF-only info, no DWARF type data (or unresolved). */
typedef enum {
    SYM_KIND_UNKNOWN = 0,
    SYM_KIND_FUNC,      /* function */
    SYM_KIND_INT,       /* integer / float base type */
    SYM_KIND_STRUCT,    /* DW_TAG_structure_type */
    SYM_KIND_UNION,     /* DW_TAG_union_type */
    SYM_KIND_ENUM,      /* DW_TAG_enumeration_type */
    SYM_KIND_ARRAY,     /* DW_TAG_array_type */
    SYM_KIND_POINTER    /* DW_TAG_pointer_type */
} symbol_kind_t;

typedef enum {
    ARG_INT    = 0,
    ARG_STRING = 1,
    ARG_SYMBOL = 2   /* bare symbol name: pass the symbol's current VALUE */
} arg_type_t;

typedef struct {
    char          name[MAX_NAME_LEN];
    unsigned long addr;
    unsigned long size;
    sym_type_t    type;         /* coarse ELF type (SYM_OBJECT / SYM_FUNC) */
    symbol_kind_t kind;         /* fine DWARF type (resolved later), SYM_KIND_UNKNOWN if n/a */
    int           struct_idx;   /* index into g_dbg.structs[] for SYM_KIND_STRUCT,
                                   or the ELEMENT struct index for SYM_KIND_ARRAY,
                                   else -1 */
    unsigned long dwarf_type_ref; /* DW_AT_type reference for diagnostics */
    int           has_dwarf;    /* 1 if DWARF type resolver touched this symbol */
} symbol_t;

/* struct member names rarely exceed 128 chars; keeping this small lets us
 * grow MAX_STRUCTS without a proportional RAM blow-up (struct_info_t holds
 * MAX_STRUCT_FIELDS of these inline). */
#define MAX_FIELD_NAME_LEN 128
typedef struct {
    char            name[MAX_FIELD_NAME_LEN];
    unsigned long   offset;     /* byte offset within struct */
    unsigned long   size;       /* size of this member in bytes */
    unsigned long   type_ref;   /* DW_AT_type ref for size resolution */
    unsigned long   arr_count;      /* >1 → array member: element count */
    unsigned long   arr_elem_size;  /* array member: per-element size */
} struct_field_t;

typedef struct {
    unsigned long   die_offset;   /* absolute offset in .debug_info */
    unsigned long   byte_size;    /* DW_AT_byte_size value */
} type_size_entry_t;
#define MAX_BASE_TYPE_SIZES 65536

typedef struct {
    char            name[MAX_NAME_LEN];
    unsigned long   die_offset;  /* DW_TAG_structure_type DIE offset */
    unsigned long   size;        /* total struct byte size */
    struct_field_t *fields;      /* 动态分配（容量 fields_cap，按需倍增），仅解析到的结构体占用内存 */
    int             field_count; /* 已解析成员数 */
    int             fields_cap;  /* fields 当前容量（上限 MAX_STRUCT_FIELDS） */
} struct_info_t;

typedef struct {
    arg_type_t    type;
    unsigned long int_val;
    unsigned long sym_addr;   /* ARG_SYMBOL: symbol address */
    unsigned long sym_size;   /* ARG_SYMBOL: symbol byte size */
    char          str_val[MAX_STR_ARG];
} func_arg_t;

typedef struct {
    pid_t pid;
} child_entry_t;

/* 'loadso' 加载记录：记录每次加载的 so 路径与符号在 so_sym_table 中的
 * 区间，供 'unloadso' 反查并卸载该 so 的全部符号。 */
typedef struct {
    char path[SO_PATH_MAX];  /* 用户输入的 so 路径(如 /opt/lnxall_app/lib/libx.so) */
    char base[SO_BASE_MAX];  /* basename(如 libx.so)，用于文件名匹配 */
    int  sym_start;          /* 本次加载符号在 so_sym_table 中的起始下标 */
    int  sym_count;          /* 本次加载的符号个数 */
} so_load_entry_t;

typedef struct {
    pid_t        target_pid;
    int          is_attached;
    int          is_pie;
    unsigned long base_addr;
    char         exe_path[512];
    symbol_t     sym_table[MAX_SYMBOLS];
    int          sym_count;
    /* Symbols loaded from shared objects via the 'loadso' command.
     * Addresses are process-space (load base already added). */
    symbol_t     so_sym_table[MAX_SYMBOLS];
    int          so_sym_count;
    so_load_entry_t so_loads[MAX_SO_LOADS];  /* 'loadso' 历史记录，供 'unloadso' 反查 */
    int          so_load_count;
    int          verbose;   /* 调试信息开关('verbose on/off')，默认关 */
    /* Out-parameter / scratch symbols created by '<type> <name> = <val>'.
     * Backed by debugger-process heap copies (plain malloc); sym->addr is
     * a DEBUGGER address, never a target-process address. On each 'call'
     * the debugger stages the copy on the target stack and copies the
     * result back afterwards. Copies are freed on attach/detach. */
    symbol_t     local_sym_table[MAX_LOCAL_SYMS];
    int          local_sym_count;
    child_entry_t children[MAX_CHILDREN];
    int          child_count;

    /* DWARF struct type info（动态分配：dwarf_parse_types 内 calloc。
     * 原内嵌 structs[16384]*19KB 的静态 BSS 达 ~300MB，嵌入式设备
     * 启动即 OOM；改为指针 + structs_max 容量，按需倍增扩容） */
    struct_info_t *structs;
    int            structs_max;
    int            struct_count;

    /* Function-call saved state (gdb-style synchronous infcall) */
    int                    call_in_progress;
    int                    call_sync_done;   /* call finished, target left stopped (auto-resumed by cmd_call_function) */
    int                    call_stopped_in_frame; /* abort kept target stopped INSIDE the callee (no PC rewind) */
    arch_regs_t saved_regs;      /* pre-call register snapshot */
    unsigned long          breakpoint_addr;  /* where the return-breakpoint sits */
    unsigned char          breakpoint_orig[8]; /* original instruction bytes */
    int                    breakpoint_len;   /* 4 (ARM64 BRK #0) */
    unsigned long          nop_slot_addr;    /* return-BRK slot, recomputed per 'call' (0=none) */
    unsigned long          call_return_value;
    int                    call_has_retval;
    char                   call_func_name[MAX_NAME_LEN];
    pid_t                  thread_list[MAX_THREADS]; /* sibling threads stopped for the call */
    int                    thread_count;
    /* infcall 期间由目标进程新创建的线程（如 pthread_create）。这些线程
     * 必须保持运行，其 ptrace 停止事件不能被 call_wait_for_return 丢弃，
     * 否则新线程会永久卡死；登记后 resume_all_threads/do_detach 可统一
     * 管理。stop_all_threads 时会重新经 /proc/<pid>/task 枚举，故先清空。 */
    pid_t                  new_threads[MAX_THREADS];
    int                    new_thread_count;
} dbg_state_t;

/* --- DWARF lookup-list types & limits. --- */
#define MAX_STRUCT_OFFSETS 65536
#define MAX_VAR_REFS       32768   /* 省内存：变量类型引用上限，超出时诊断截断 */
#define MAX_TYPEDEF_REFS   65536

typedef struct {
    unsigned long  die_offset;    /* absolute offset in .debug_info */
    int            struct_idx;    /* index into g_dbg.structs[] */
} struct_offset_t;

typedef struct {
    char           name[MAX_NAME_LEN];
    unsigned long  type_ref;      /* section-absolute DW_AT_type offset in .debug_info */
} var_ref_t;

typedef struct {
    unsigned long  td_offset;     /* offset of the typedef DIE itself */
    unsigned long  target_ref;    /* DW_AT_type of the typedef */
} typedef_ref_t;

typedef struct {
    unsigned long  arr_offset;    /* offset of the DW_TAG_array_type DIE */
    unsigned long  elem_ref;      /* DW_AT_type of the array element */
    unsigned long  elem_count;    /* element count (subrange-derived) */
} array_ref_t;
#define MAX_ARRAY_REFS 65536

/* ========================================================================
 * Global State (definitions live in their owning modules)
 * ======================================================================== */

extern dbg_state_t g_dbg;                       /* owned by main.c */
extern volatile sig_atomic_t g_sigchld_ready;   /* owned by thread_ops.c */
extern volatile sig_atomic_t g_intr_requested;  /* owned by main.c: Ctrl-C
                                                   during a call / at REPL */

/* DWARF type-resolution working lists (owned by dwarf_parse.c) */
extern struct_offset_t   g_so_list[MAX_STRUCT_OFFSETS];
extern var_ref_t         g_vr_list[MAX_VAR_REFS];
extern typedef_ref_t     g_td_list[MAX_TYPEDEF_REFS];
extern type_size_entry_t g_ts_list[MAX_BASE_TYPE_SIZES];
extern array_ref_t       g_arr_list[MAX_ARRAY_REFS];
extern int g_so_count;
extern int g_vr_count;
extern int g_arr_count;
extern int g_td_count;
extern int g_ts_count;

/* ========================================================================
 * Cross-module function prototypes
 * ======================================================================== */

/* --- main.c: utility / REPL --- */
char *safe_strcpy(char *dst, const char *src, size_t size);
char *trim(char *s);
int parse_int_value(const char *s, unsigned long *out);
int parse_hex_bytes(const char *s, unsigned char *out, size_t max_out);
int base_type_lookup(const char *spec, unsigned long *out_size);
int exec_command(char *line);
void log_user_command(const char *line);

/* --- cmd_attach.c --- */
int do_attach(pid_t pid);
int do_detach(void);

/* --- cmd_d.c --- */
int cmd_dump_memory(const char *spec);
int cmd_read_var(const char *spec);
int cmd_print_struct_ptr(const char *struct_name, const char *addr_spec);
int display_struct_var(const char *var_name, unsigned long addr,
                       unsigned long size, struct_info_t *si);
int display_var_array(const char *var_name, unsigned long addr,
                      unsigned long elem_count, unsigned long elem_size,
                      struct_info_t *elem_struct);
int display_array_field(const char *var_name, unsigned long base,
                        struct_field_t *f);
int read_printable_string(unsigned long addr, unsigned long count,
                          char *out, size_t out_sz);
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);

/* --- cmd_m.c --- */
int cmd_write_var(const char *spec, const char *val_str);
int cmd_write_memory(const char *spec, const char *val_str);

/* --- cmd_call.c --- */
int cmd_call_function(const char *spec);
int call_hit_break(const arch_regs_t *r, unsigned long bp_addr);
int call_restore_break(void);
int complete_pending_call(pid_t pid);
int call_wait_for_return(void);
void abort_call_and_restore(void);
void abort_call_keep_frame(void);

/* --- cmd_so.c --- */
int cmd_load_so(const char *path);
int cmd_unload_so(const char *path);
int elf_parse_so_symbols(const char *path);
unsigned long find_so_load_base(pid_t pid, const char *path);

/* --- cmd_struct.c --- */
int cmd_create_local(const char *spec);
int find_struct_by_name(const char *name);
int cmd_ptype(const char *tname);

/* --- cmd_symbol.c --- */
const char *sym_kind_name(symbol_kind_t kind);
int cmd_print_addr(const char *name);
int cmd_lookup_symbol_by_addr(unsigned long addr);

/* --- thread_ops.c: 线程操作/SIGCHLD/事件处理 + 线程排障命令 --- */
void sigchld_handler(int sig);
int  sigchld_notify_init(void);   /* 建 self-pipe（须先于 sigaction(SIGCHLD)） */
int  sigchld_notify_fd(void);     /* 通知管道读端（供 select 监听） */
void sigchld_notify_drain(void);  /* 读空通知管道（水平触发复位） */
void handle_child_status(pid_t pid, int status);
void handle_side_thread_stop(pid_t tid, int status);
void process_child_events(void);
int stop_all_threads(void);
void resume_all_threads(void);
int ptrace_stop_target(pid_t pid);
int ptrace_continue_target(pid_t pid);
int target_freeze(void);
void target_thaw(void);
int target_read_mem(unsigned long addr, void *buf, size_t len);
int cmd_threads_dump(void);    /* 排障命令 'threads' */
int cmd_resume_tid(pid_t tid); /* 排障命令 'resume <tid>' */

/* --- mem_rw.c --- */
int mem_read(pid_t pid, unsigned long addr, void *buf, size_t len);
int mem_write(pid_t pid, unsigned long addr, const void *buf, size_t len);
int mem_read_word(pid_t pid, unsigned long addr, unsigned long *val);
int read_any_mem(unsigned long addr, void *buf, size_t len);

/* ------------------------------------------------------------------------
 * 位数无关 ELF 解析公共结构（symbol_parse.c 实现，dwarf_parse.c 复用）
 *
 * ELF32（Elf32_*）与 ELF64（Elf64_*）的头/section 布局不同，统一经
 * elf_read_file 转成下列与位数无关的结构后再消费；文件偏移/大小字段
 * 用 unsigned long 承载（32 位平台 4 字节，64 位平台 8 字节）。
 * ------------------------------------------------------------------------ */
typedef struct {
    char          *name;      /* 指向 hdr.shstrtab 内字符串（加载后回填） */
    unsigned long  name_off;  /* sh_name：shstrtab 内偏移（内部解析用） */
    unsigned long  type;      /* SHT_* */
    unsigned long  offset;    /* sh_offset：文件内偏移 */
    unsigned long  size;      /* sh_size */
} elf_section_t;

typedef struct {
    int            is_elf64;  /* 1 = ELFCLASS64，0 = ELFCLASS32 */
    unsigned short e_type;    /* ET_DYN / ET_EXEC */
    unsigned long  e_shoff;   /* section 头表文件偏移 */
    unsigned short e_shentsize;/* section 头表条目大小 */
    unsigned short e_shnum;   /* section 数 */
    unsigned short e_shstrndx;/* section 名字符串表索引 */
    elf_section_t *shdrs;     /* e_shnum 项 */
    char          *shstrtab;  /* section 名字符串表 */
} elf_file_hdr_t;

/* 打开 path，校验 ELF 魔数并解析头/section 表/shstrtab 到 hdr。
 * 成功时 *out_fp 返回已打开的文件指针；失败时文件已关闭、hdr 无需释放。
 * 解析完成必须调用 elf_free_file 释放 hdr 内部分配，并 fclose(*out_fp)。 */
int  elf_read_file(const char *path, FILE **out_fp, elf_file_hdr_t *hdr);
void elf_free_file(elf_file_hdr_t *hdr);

/* --- symbol_parse.c: ELF 符号表 / 路径基址 / 符号查询 --- */
int elf_parse_common(const char *path, symbol_t *table, int *count,
                     unsigned long *out_pie_flag, int require_dyn);
int elf_parse_symbols(const char *path, unsigned long *pie_flag);
int resolve_exe_path(pid_t pid, char *out, size_t out_sz);
unsigned long find_load_base(pid_t pid, const char *path);
void adjust_symbol_addresses(void);
int is_local_symbol(const symbol_t *s);
symbol_t *find_symbol(const char *name, sym_type_t want_type);
symbol_t *find_symbol_any(const char *name);

/* --- dwarf_parse.c: DWARF 类型解析与运行期类型内省 --- */
int dwarf_parse_types(const char *path);
struct_info_t *find_struct_by_die_offset(unsigned long off);
struct_info_t *find_struct_by_size(unsigned long size);
unsigned long resolve_typedef_chain_rt(unsigned long ref);
unsigned long resolve_array_elem_ref_rt(unsigned long type_ref);
int resolve_var_array_rt(const symbol_t *sym,
                         unsigned long *out_count,
                         unsigned long *out_elem_size,
                         struct_info_t **out_struct);

#endif /* LNXALL_TRACE_H */
