OXYGENHUB
◆ rrdc-perf enhanced-x16-emulator / src / dbg_info.h
9.8 KiB · Objective-C · last changed chore(): initial commit 25 days ago source blame history raw
9120e874 Andy McCall 1
#ifndef _DBG_INFO_H_
2
#define _DBG_INFO_H_
3
4
#include <stdint.h>
5
#include <stdbool.h>
6
7
#ifdef __cplusplus
8
extern "C" {
9
#endif
10
11
// A debug-info address. Flat 24-bit: bits 0-15 are the CPU address, bits 16-23
12
// the 65C816 program bank. On the 65C02 the high byte is simply zero. Code on a
13
// GS/Gen2 machine lives above $FFFF, so a 16-bit address cannot describe it.
14
typedef uint32_t dbg_addr_t;
15
16
// How confident a banked lookup is about the answer it gave.
17
typedef enum {
18
	DBG_BANK_NO_MATCH = 0, // no debug info covers this address
19
	DBG_BANK_RESOLVED,     // matched a segment whose RAM bank is known
20
	DBG_BANK_UNKNOWN,      // matched, but which bank this segment belongs to
21
	                       // was never established, so the answer may belong to
22
	                       // a different bank's segment at the same address
23
} dbg_bank_result_t;
24
25
// Load and parse a cc65 .dbg file. Returns 0 on success, -1 on error.
26
int dbg_info_load(const char *path);
27
28
// Look up source location for a given address.
29
// Returns true if found, fills in file_path and line_num.
30
// file_path points to internal storage — do not free.
31
bool dbg_info_addr_to_source(dbg_addr_t addr, const char **file_path, int *line_num);
32
33
// Like dbg_info_addr_to_source, but returns the line whose span *encloses* addr
34
// (nearest line starting at or below addr and covering it). This keeps the
35
// current-line highlight correct when the PC lands in the middle of a multi-byte
36
// instruction while stepping.
37
bool dbg_info_addr_to_source_nearest(dbg_addr_t addr, const char **file_path, int *line_num);
38
39
// Directory of the most recently loaded .dbg file (for locating source files).
40
// Returns an empty string if no .dbg has been loaded or it had no directory part.
41
const char *dbg_info_get_dbg_dir(void);
42
43
// True when the loaded debug info carries cc65 high-level (C) line records, so
44
// a source line means a whole C statement rather than one instruction. The
45
// debugger uses this to decide whether stepping by line is worth offering.
46
bool dbg_info_has_high_level(void);
47
48
// Look up address for a given source location.
49
// Returns true if found, fills in addr.
50
bool dbg_info_source_to_addr(const char *file_path, int line_num, dbg_addr_t *addr);
51
52
// Check if debug info is loaded
53
bool dbg_info_is_loaded(void);
54
55
// Disassembly alignment helper: returns true if `addr` is the start address of
56
// a known cc65 .dbg span/line (i.e. a compiler-emitted instruction boundary).
57
// Used by the anchored disassembler (code_map) as a fallback alignment anchor
58
// when live execution coverage is unavailable for that address.
59
bool dbg_info_is_span_start(dbg_addr_t addr);
60
61
// Remove all debug mappings in an address range (for module swap)
62
void dbg_info_unload_range(dbg_addr_t start, dbg_addr_t end);
63
64
// Peek at a .dbg file's segment range without loading it.
65
// Returns true if a matching .dbg file exists and has valid segments.
66
bool dbg_info_peek_file_range(const char *loaded_path, dbg_addr_t *out_start, dbg_addr_t *out_end);
67
68
// Auto-load .dbg file matching a loaded binary. Unloads overlapping range first.
69
// Returns 0 on success, -1 if no .dbg found.
70
// NOTE: this unloads the min/max span of every segment the .dbg declares before
71
// re-parsing, which for a normal cc65 program runs from the zero page to the top
72
// of the program. That is wider than what the load actually overwrote, so it
73
// also drops other modules' records in that window -- including debug info
74
// loaded with -dbgfile, which nothing re-merges.
75
//
76
// It cannot simply be narrowed. Segment, span, line and label records are still
77
// appended unconditionally -- only file and equate records are reused -- so a
78
// range that misses this module's own BSS and zero-page records leaves them
79
// behind while adding fresh copies, and they accumulate until an address can be
80
// described by a module that is no longer resident. Evicting other modules and
81
// replacing this one's own records want different ranges.
82
//
83
// Records do now carry the module they came from, but only the deduplicated
84
// ones and dbg_seg_t. Finishing this means giving dbg_span_t/dbg_line_t/
85
// dbg_sym_t the same owner field and having dbg_info_unload_range() drop by
86
// owner rather than purely by address.
87
//
88
// NOTE: load_addr is currently ignored -- the debug info always describes the
89
// program at its link-time addresses. A relocating load (secondary address 0)
90
// therefore reports source lines for where the program was linked, not where it
91
// actually landed.
92
int dbg_info_load_for_file(const char *loaded_path, dbg_addr_t load_addr);
93
94
/* Address -> source, disambiguated by the X16 RAM bank currently mapped at
95
 * $A000-$BFFF. Programs routinely place several segments at $A000 (one per RAM
96
 * bank); the .dbg records no bank, so a banked address otherwise matches every
97
 * one of them and the reported file/line is effectively arbitrary. Pass the
98
 * live RAM bank (memory_get_ram_bank()) to pick the right one; pass -1 to skip
99
 * bank filtering. dbg_info_addr_to_source_nearest() is the ram_bank = -1 form.
100
 *
101
 * Segments whose bank could not be established stay eligible, so a mapping is
102
 * never lost -- but the answer may then belong to another bank's segment at the
103
 * same address. Use the _ex form to tell the two cases apart and say so, rather
104
 * than showing a confident file/line that might be from the wrong bank. */
105
bool dbg_info_addr_to_source_banked(dbg_addr_t addr, int ram_bank,
106
                                    const char **file_path, int *line_num);
107
108
dbg_bank_result_t dbg_info_addr_to_source_banked_ex(dbg_addr_t addr, int ram_bank,
109
                                                    const char **file_path, int *line_num);
110
111
/* Tell the debug info that a runtime LOAD placed `size` bytes at `load_addr`
112
 * while RAM bank `ram_bank` was mapped. When that uniquely identifies a banked
113
 * segment, the segment is associated with that bank. No-op outside
114
 * $A000-$BFFF. (Banks are also seeded from RAM_BANK_* equates in the .dbg.) */
115
void dbg_info_note_bank_load(dbg_addr_t load_addr, uint32_t size, uint8_t ram_bank);
116
117
// Free all loaded debug info
118
void dbg_info_free(void);
119
120
// ---- Symbol / label lookups (from cc65 .dbg `sym` records) ------------------
121
// Symbol names point to internal storage owned by the loaded debug info. Unlike
122
// file paths, they do NOT survive a module swap: dbg_info_unload_range() frees
123
// the names of the symbols it drops. Copy anything that has to outlive a load
124
// or unload.
125
// Address label at exactly `addr` (type=lab). `name` points to internal storage
126
// — do not free. Returns false if none.
127
bool dbg_info_addr_to_label(dbg_addr_t addr, const char **name);
128
129
// Label that `addr` falls inside: the nearest one at or below it, with its own
130
// address returned in `label_addr` so callers can render "name+offset".
131
//
132
// A return address on the stack points just past a JSR, which is almost never
133
// exactly a label, so an exact lookup leaves every caller frame anonymous. This
134
// is what the Call Stack needs to name its frames.
135
//
136
// It will happily match a far-away label for an address the debug info does not
137
// really cover, so only trust it where the address is known to be in mapped
138
// code (e.g. when dbg_info_addr_to_source_banked() also succeeds).
139
bool dbg_info_addr_to_label_nearest(dbg_addr_t addr, const char **name, dbg_addr_t *label_addr);
140
141
// Address of a label by name (case-insensitive, exact match). Returns false if
142
// no such label.
143
bool dbg_info_label_to_addr(const char *name, dbg_addr_t *addr);
144
145
// Value of a cc65 `equ` record by name (case-insensitive). Equates are the
146
// KERNAL entry points, hardware register names, zero-page variable addresses
147
// and plain constants a program defines; they are deliberately kept out of the
148
// label map (which stays a clean address→name map for the disassembler) but are
149
// exactly what a user hovers in source. Returns false if no such equate.
150
bool dbg_info_equate_to_value(const char *name, dbg_addr_t *val);
151
152
// What kind of name dbg_info_name_to_value() resolved.
153
#define DBG_NAME_LABEL  0
154
#define DBG_NAME_EQUATE 1
155
156
// Resolve any name the debug info knows: program labels first, then equates.
157
// `kind` (optional) receives DBG_NAME_LABEL or DBG_NAME_EQUATE.
158
bool dbg_info_name_to_value(const char *name, dbg_addr_t *val, int *kind);
159
160
// Enumerate all address labels (sorted by address). dbg_info_symbol_at fills
161
// `name` (internal storage) and `addr` for 0 <= index < dbg_info_symbol_count().
162
int  dbg_info_symbol_count(void);
163
bool dbg_info_symbol_at(int index, const char **name, dbg_addr_t *addr);
164
165
// ---- Source-file enumeration (for the debugger's file picker) ---------------
166
// Maximum path length used by dbg_info_scan_dbg_files().
167
#define DBG_INFO_PATH_MAX 260
168
169
// Enumerate the source files referenced by the loaded .dbg (by the name as
170
// recorded — usually a basename). Lets the debugger pre-open any known source
171
// file to set breakpoints / run-to before the PC reaches it. `name` points to
172
// internal storage — do not free. Valid for 0 <= index < dbg_info_file_count().
173
//
174
// When the .dbg carries cc65 high-level (C) line info, the ".s" files cc65
175
// generated on the way from C to the assembler are left out: they are not what
176
// the user wrote, and cl65 deletes them, so offering them opens a file that is
177
// not there. A hand-written .s stays on offer — see refresh_line_type_state()
178
// for exactly what has to hold before one is treated as generated. The indices
179
// are dense either way, so a caller walks 0..count-1 as before.
180
int  dbg_info_file_count(void);
181
bool dbg_info_file_at(int index, const char **name);
182
183
// Scan a directory (non-recursive) for cc65 ".dbg" files, writing up to `max`
184
// full paths into `out`. Portable (uses dirent). Safe if dir is NULL/empty.
185
// Returns the number of paths written. Lets the debugger surface other .dbg
186
// modules that the running code may LOAD later, so their sources/line
187
// breakpoints can be queued up ahead of time.
188
int  dbg_info_scan_dbg_files(const char *dir, char out[][DBG_INFO_PATH_MAX], int max);
189
190
#ifdef __cplusplus
191
}
192
#endif
193
194
#endif