-
Notifications
You must be signed in to change notification settings - Fork 37
/
Copy pathsymbols.c
1093 lines (996 loc) · 29.3 KB
1
2
3
/*
* Hatari - symbols.c
*
4
* Copyright (C) 2010-2024 by Eero Tamminen
5
*
6
7
* This file is distributed under the GNU General Public License, version 2
* or at your option any later version. Read the file gpl.txt for details.
8
9
10
11
*
* symbols.c - Hatari debugger symbol/address handling; parsing, sorting,
* matching, TAB completion support etc.
*
12
* Symbol/address information is read either from:
13
* - A program file's symbol table (in DRI/GST, a.out, or ELF format), or
14
15
16
17
18
* - ASCII file which contents are subset of "nm" output i.e. composed of
* a hexadecimal addresses followed by a space, letter indicating symbol
* type (T = text/code, D = data, B = BSS), space and the symbol name.
* Empty lines and lines starting with '#' are ignored. It's AHCC SYM
* output compatible.
19
*/
20
const char Symbols_fileid[] = "Hatari symbols.c";
21
22
23
24
25
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
26
#include "main.h"
27
28
#include "file.h"
#include "options.h"
29
#include "symbols.h"
30
31
#include "debugui.h"
#include "debug_priv.h"
32
#include "debugInfo.h"
33
#include "evaluate.h"
34
#include "configuration.h"
35
#include "a.out.h"
36
#include "maccess.h"
37
38
39
#include "symbols-common.c"
40
/* how many characters the symbol name can have.
41
42
43
*
* While DRI/GST symbols are at max only couple of dozen
* chars long, C++/a.out symbols can be almost of any size.
44
*/
45
46
#define MAX_SYM_SIZE 1024
#define MAX_SYM_SIZE_S "1024"
47
48
49
50
51
/* TODO: add symbol name/address file names to configuration? */
static symbol_list_t *CpuSymbolsList;
static symbol_list_t *DspSymbolsList;
52
53
/* path for last loaded program (through GEMDOS HD emulation) */
static char *CurrentProgramPath;
54
/* prevent repeated failing on every debugger invocation */
55
static bool AutoLoadFailed;
56
57
58
59
60
61
62
63
typedef enum {
SYMBOLS_FOR_NONE,
SYMBOLS_FOR_USER,
/* autoload facilities */
SYMBOLS_FOR_TOS,
SYMBOLS_FOR_PROGRAM,
} symbols_for_t;
64
65
66
/* what triggered current CPU symbols to be loaded */
static symbols_for_t CpuSymbolsAreFor = SYMBOLS_FOR_NONE;
67
68
69
70
71
72
73
/**
* Load symbols of given type and the symbol address addresses from
* the given ASCII file and add given offsets to the addresses.
* Return symbols list or NULL for failure.
*/
74
75
static symbol_list_t* symbols_load_ascii(FILE *fp, uint32_t *offsets, uint32_t maxaddr,
symtype_t gettype, const symbol_opts_t *opts)
76
77
{
symbol_list_t *list;
78
79
char symchar, name[MAX_SYM_SIZE+1];
char *buf, buffer[MAX_SYM_SIZE+64];
80
int count, line, symbols;
81
uint32_t address, offset;
82
ignore_counts_t ignore;
83
84
85
symtype_t symtype;
/* count content lines */
86
line = symbols = 0;
87
while (fgets(buffer, sizeof(buffer), fp)) {
88
89
line++;
90
91
/* skip comments (AHCC SYM file comments start with '*') */
if (*buffer == '#' || *buffer == '*') {
92
93
94
continue;
}
/* skip empty lines */
95
for (buf = buffer; isspace((unsigned char)*buf); buf++);
96
97
98
if (!*buf) {
continue;
}
99
if (!isxdigit((unsigned char)*buf)) {
100
101
102
fprintf(stderr, "ERROR: line %d doesn't start with an address.\n", line);
return NULL;
}
103
104
symbols++;
}
105
106
if (!symbols) {
fprintf(stderr, "ERROR: no symbols.\n");
107
return NULL;
108
109
}
110
111
fseek(fp, 0, SEEK_SET);
112
113
/* allocate space for symbol list & names */
if (!(list = symbol_list_alloc(symbols))) {
114
115
116
return NULL;
}
117
118
119
count = 0;
memset(&ignore, 0, sizeof(ignore));
120
121
/* read symbols */
for (line = 1; fgets(buffer, sizeof(buffer), fp); line++) {
122
123
/* skip comments (AHCC SYM file comments start with '*') */
if (*buffer == '#' || *buffer == '*') {
124
125
126
continue;
}
/* skip empty lines */
127
for (buf = buffer; isspace((unsigned char)*buf); buf++);
128
129
130
if (!*buf) {
continue;
}
131
132
133
134
/* file not modified in meanwhile? */
assert(count < symbols);
/* C++ symbols can contain almost any characters */
if (sscanf(buffer, "%x %c %"MAX_SYM_SIZE_S"[^$?@;\n]\n", &address, &symchar, name) != 3) {
135
fprintf(stderr, "WARNING: syntax error on line %d, skipping.\n", line);
136
137
continue;
}
138
switch (toupper((unsigned char)symchar)) {
139
140
141
142
case 'T':
symtype = SYMTYPE_TEXT;
offset = offsets[0];
break;
143
144
145
146
case 'W': /* ELF 'nm' code symbol type, weak */
symtype = SYMTYPE_WEAK;
offset = offsets[0];
break;
147
case 'O': /* AHCC type for _StkSize etc */
148
149
case 'V': /* ELF 'nm' data symbol type, weak */
case 'R': /* ELF 'nm' data symbol type, read only */
150
151
152
153
154
155
156
157
case 'D':
symtype = SYMTYPE_DATA;
offset = offsets[1];
break;
case 'B':
symtype = SYMTYPE_BSS;
offset = offsets[2];
break;
158
case 'A':
159
/* absolute address or arbitrary constant value */
160
161
162
symtype = SYMTYPE_ABS;
offset = 0;
break;
163
default:
164
fprintf(stderr, "WARNING: unrecognized symbol type '%c' on line %d, skipping.\n", symchar, line);
165
ignore.invalid++;
166
167
continue;
}
168
if (!(gettype & symtype)) {
169
170
continue;
}
171
address += offset;
172
if (address > maxaddr && symtype != SYMTYPE_ABS) {
173
fprintf(stderr, "WARNING: invalid address 0x%x on line %d, skipping.\n", address, line);
174
175
176
177
178
ignore.invalid++;
continue;
}
/* whether to ignore symbol based on options and its name & type */
if (ignore_symbol(name, symtype, opts, &ignore)) {
179
180
continue;
}
181
list->names[count].address = address;
182
183
list->names[count].type = symtype;
list->names[count].name = strdup(name);
184
list->names[count].name_allocated = true;
185
186
187
assert(list->names[count].name);
count++;
}
188
show_ignored(&ignore);
189
list->symbols = symbols;
190
list->namecount = count;
191
192
193
return list;
}
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
/**
* Return true if symbol name has (C++) data symbol prefix
*/
static bool is_cpp_data_symbol(const char *name)
{
static const char *cpp_data[] = {
"typeinfo ",
"vtable ",
"VTT "
};
int i;
for (i = 0; i < ARRAY_SIZE(cpp_data); i++) {
size_t len = strlen(cpp_data[i]);
if (strncmp(name, cpp_data[i], len) == 0) {
return true;
}
}
return false;
}
/**
* (C++) compiler can put certain data members to text section, and
* some of the weak (C++) symbols are for data. For C++, these can be
* recognized by their name. This changes their type to data, to
* speed up text symbol searches in profiler.
*/
static int fix_symbol_types(symbol_list_t* list)
{
symbol_t *sym = list->names;
int i, count, changed = 0;
count = list->namecount;
for (i = 0; i < count; i++) {
if (!(sym[i].type & SYMTYPE_CODE)) {
continue;
}
if (is_cpp_data_symbol(sym[i].name)) {
sym[i].type = SYMTYPE_DATA;
changed++;
}
/* TODO: add check also for C++ data member
* names, similar to profiler post-processor
* (requires using regex)?
*/
}
return changed;
}
242
/**
243
* Separate code symbols from other symbols in address list.
244
*/
245
static void symbols_split_addresses(symbol_list_t* list)
246
247
{
symbol_t *sym = list->addresses;
248
uint32_t prev = 0;
249
250
251
int i;
for (i = 0; i < list->namecount; i++) {
252
253
254
if (sym[i].type & ~SYMTYPE_CODE) {
break;
}
255
if (sym[i].address < prev) {
256
257
258
char stype = symbol_char(sym[i].type);
fprintf(stderr, "INTERNAL ERROR: %c symbol %d/%d ('%s') at %x < %x (prev addr)\n",
stype, i, list->namecount, sym[i].name, sym[i].address, prev);
259
260
261
exit(1);
}
prev = sym[i].address;
262
}
263
264
list->codecount = i;
list->datacount = list->namecount - i;
265
266
}
267
268
269
270
271
272
273
274
/**
* Set sections to match running process by adding TEXT/DATA/BSS
* start addresses to section offsets and ends, and return true if
* results match it.
*/
static bool update_sections(prg_section_t *sections)
{
/* offsets & max sizes for running program TEXT/DATA/BSS section symbols */
275
uint32_t start = DebugInfo_GetTEXT();
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
if (!start) {
fprintf(stderr, "ERROR: no valid program basepage!\n");
return false;
}
sections[0].offset = start;
sections[0].end += start;
if (DebugInfo_GetTEXTEnd() != sections[0].end) {
fprintf(stderr, "ERROR: given program TEXT section size differs from one in RAM!\n");
return false;
}
start = DebugInfo_GetDATA();
sections[1].offset = start;
if (sections[1].offset != sections[0].end) {
fprintf(stderr, "WARNING: DATA start doesn't match TEXT start + size!\n");
}
sections[1].end += start;
start = DebugInfo_GetBSS();
sections[2].offset = start;
if (sections[2].offset != sections[1].end) {
fprintf(stderr, "WARNING: BSS start doesn't match DATA start + size!\n");
}
sections[2].end += start;
return true;
}
304
305
306
307
308
/**
* Load symbols of given type and the symbol address addresses from
* the given file and add given offsets to the addresses.
* Return symbols list or NULL for failure.
*/
309
static symbol_list_t* Symbols_Load(const char *filename, uint32_t *offsets, uint32_t maxaddr, symtype_t gettype)
310
311
{
symbol_list_t *list;
312
symbol_opts_t opts;
313
int changed, dups;
314
FILE *fp;
315
316
317
if (!File_Exists(filename)) {
fprintf(stderr, "ERROR: file '%s' doesn't exist or isn't readable!\n", filename);
318
319
return NULL;
}
320
321
322
memset(&opts, 0, sizeof(opts));
opts.no_gccint = true;
opts.no_local = true;
323
opts.no_dups = true;
324
325
if (Opt_IsAtariProgram(filename)) {
326
const char *last = CurrentProgramPath;
327
328
329
330
331
if (!last) {
/* "pc=text" breakpoint used as point for loading program symbols gives false hits during bootup */
fprintf(stderr, "WARNING: no program loaded yet (through GEMDOS HD emu)!\n");
} else if (strcmp(last, filename) != 0) {
fprintf(stderr, "WARNING: given program doesn't match last program executed by GEMDOS HD emulation:\n\t%s\n", last);
332
}
333
fprintf(stderr, "Reading symbols from program '%s' symbol table...\n", filename);
334
fp = fopen(filename, "rb");
335
list = symbols_load_binary(fp, &opts, update_sections);
336
337
} else {
fprintf(stderr, "Reading 'nm' style ASCII symbols from '%s'...\n", filename);
338
fp = fopen(filename, "r");
339
list = symbols_load_ascii(fp, offsets, maxaddr, gettype, &opts);
340
}
341
342
fclose(fp);
343
if (!list) {
344
fprintf(stderr, "ERROR: reading symbols from '%s' failed!\n", filename);
345
346
347
return NULL;
}
348
349
350
351
352
353
if (!list->namecount) {
fprintf(stderr, "ERROR: no valid symbols in '%s', loading failed!\n", filename);
symbol_list_free(list);
return NULL;
}
354
355
356
357
if ((changed = fix_symbol_types(list))) {
fprintf(stderr, "Corrected type for %d symbols (text->data).\n", changed);
}
358
359
360
361
362
363
364
365
366
/* first sort symbols by address, _with_ code symbols being first */
qsort(list->names, list->namecount, sizeof(symbol_t), symbols_by_address);
/* remove symbols with duplicate addresses? */
if (opts.no_dups) {
if ((dups = symbols_trim_names(list))) {
fprintf(stderr, "Removed %d symbols in same addresses as other symbols.\n", dups);
}
}
367
368
/* copy name list to address list */
369
list->addresses = malloc(list->namecount * sizeof(symbol_t));
370
assert(list->addresses);
371
memcpy(list->addresses, list->names, list->namecount * sizeof(symbol_t));
372
373
/* "split" address list to code and other symbols */
374
symbols_split_addresses(list);
375
376
377
378
379
/* finally, sort name list by names */
qsort(list->names, list->namecount, sizeof(symbol_t), symbols_by_name);
/* skip more verbose output when symbols are auto-loaded */
380
if (ConfigureParams.Debugger.bSymbolsAutoLoad) {
381
fprintf(stderr, "Skipping detailed duplicate symbols reporting when autoload is enabled.\n");
382
} else {
383
384
385
386
387
/* check for duplicate addresses? */
if (!opts.no_dups) {
if ((dups = symbols_check_addresses(list->addresses, list->namecount))) {
fprintf(stderr, "%d symbols in same addresses as other symbols.\n", dups);
}
388
}
389
390
391
392
393
394
/* report duplicate names */
if ((dups = symbols_check_names(list->names, list->namecount))) {
fprintf(stderr, "%d symbols having multiple addresses for the same name.\n"
"Symbol expansion will match only one of the addresses for them!\n",
dups);
395
}
396
}
397
398
fprintf(stderr, "Loaded %d symbols (%d for code) from '%s'.\n",
399
list->namecount, list->codecount, filename);
400
401
402
403
return list;
}
404
405
406
407
408
/**
* Free read symbols.
*/
static void Symbols_Free(symbol_list_t* list)
{
409
symbol_list_free(list);
410
411
}
412
413
414
415
416
417
418
419
/**
* Free all symbols (at exit).
*/
void Symbols_FreeAll(void)
{
symbol_list_free(CpuSymbolsList);
symbol_list_free(DspSymbolsList);
}
420
421
422
/* ---------------- symbol name completion support ------------------ */
423
424
425
/**
* Helper for symbol name completion and finding their addresses.
* STATE = 0 -> different text from previous one.
426
* Return (copy of) next name or NULL if no matches.
427
*/
428
static char* Symbols_MatchByName(symbol_list_t* list, symtype_t symtype, const char *text, int state)
429
{
430
static int i, len;
431
const symbol_t *entry;
432
433
434
435
436
437
if (!list) {
return NULL;
}
if (!state) {
438
439
440
441
442
443
/* first match */
len = strlen(text);
i = 0;
}
/* next match */
444
entry = list->names;
445
while (i < list->namecount) {
446
if ((entry[i].type & symtype) &&
447
strncmp(entry[i].name, text, len) == 0) {
448
return strdup(entry[i++].name);
449
450
451
452
453
454
455
} else {
i++;
}
}
return NULL;
}
456
/**
457
* Readline match callbacks for CPU symbol name completion.
458
459
460
461
* STATE = 0 -> different text from previous one.
* Return next match or NULL if no matches.
*/
char* Symbols_MatchCpuAddress(const char *text, int state)
462
463
464
465
{
return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_ALL, text, state);
}
char* Symbols_MatchCpuCodeAddress(const char *text, int state)
466
{
467
468
469
if (ConfigureParams.Debugger.bMatchAllSymbols) {
return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_ALL, text, state);
} else {
470
return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_CODE, text, state);
471
}
472
}
473
474
char* Symbols_MatchCpuDataAddress(const char *text, int state)
{
475
476
477
478
479
if (ConfigureParams.Debugger.bMatchAllSymbols) {
return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_ALL, text, state);
} else {
return Symbols_MatchByName(CpuSymbolsList, SYMTYPE_DATA|SYMTYPE_BSS, text, state);
}
480
}
481
482
/**
483
484
485
486
487
* Readline match callback for DSP symbol name completion.
* STATE = 0 -> different text from previous one.
* Return next match or NULL if no matches.
*/
char* Symbols_MatchDspAddress(const char *text, int state)
488
489
490
491
{
return Symbols_MatchByName(DspSymbolsList, SYMTYPE_ALL, text, state);
}
char* Symbols_MatchDspCodeAddress(const char *text, int state)
492
{
493
return Symbols_MatchByName(DspSymbolsList, SYMTYPE_CODE, text, state);
494
}
495
496
497
498
char* Symbols_MatchDspDataAddress(const char *text, int state)
{
return Symbols_MatchByName(DspSymbolsList, SYMTYPE_DATA|SYMTYPE_BSS, text, state);
}
499
500
501
502
503
/* ---------------- symbol name -> address search ------------------ */
/**
504
* Binary search symbol of given type by name.
505
506
* Return symbol if name matches, zero otherwise.
*/
507
static const symbol_t* Symbols_SearchByName(symbol_t* entries, int count, symtype_t symtype, const char *name)
508
509
510
511
512
513
{
/* left, right, middle */
int l, r, m, dir;
/* bisect */
l = 0;
514
r = count - 1;
515
516
517
do {
m = (l+r) >> 1;
dir = strcmp(entries[m].name, name);
518
if (dir == 0 && (entries[m].type & symtype)) {
519
520
521
522
523
524
525
526
527
528
529
530
return &(entries[m]);
}
if (dir > 0) {
r = m-1;
} else {
l = m+1;
}
} while (l <= r);
return NULL;
}
/**
531
532
* Set given symbol's address to variable and return true if one
* was found from given list.
533
*/
534
static bool Symbols_GetAddress(symbol_list_t* list, symtype_t symtype, const char *name, uint32_t *addr)
535
536
{
const symbol_t *entry;
537
538
539
540
if (!(list && list->names)) {
return false;
}
entry = Symbols_SearchByName(list->names, list->namecount, symtype, name);
541
542
543
544
545
546
if (entry) {
*addr = entry->address;
return true;
}
return false;
}
547
bool Symbols_GetCpuAddress(symtype_t symtype, const char *name, uint32_t *addr)
548
549
550
{
return Symbols_GetAddress(CpuSymbolsList, symtype, name, addr);
}
551
bool Symbols_GetDspAddress(symtype_t symtype, const char *name, uint32_t *addr)
552
{
553
return Symbols_GetAddress(DspSymbolsList, symtype, name, addr);
554
555
556
557
558
}
/* ---------------- symbol address -> name search ------------------ */
559
/**
560
* Binary search code symbol by address in given sorted list.
561
* Return index for symbol which address matches or precedes
562
563
* the given one.
*/
564
static int Symbols_SearchBeforeAddress(symbol_t* entries, int count, uint32_t addr)
565
566
567
{
/* left, right, middle */
int l, r, m;
568
uint32_t curr;
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
/* bisect */
l = 0;
r = count - 1;
do {
m = (l+r) >> 1;
curr = entries[m].address;
if (curr == addr) {
return m;
}
if (curr > addr) {
r = m-1;
} else {
l = m+1;
}
} while (l <= r);
return r;
}
588
static const char* Symbols_GetBeforeAddress(symbol_list_t *list, uint32_t *addr)
589
590
591
592
593
594
595
596
597
598
599
{
if (!(list && list->addresses)) {
return NULL;
}
int i = Symbols_SearchBeforeAddress(list->addresses, list->codecount, *addr);
if (i >= 0) {
*addr = list->addresses[i].address;
return list->addresses[i].name;
}
return NULL;
}
600
const char* Symbols_GetBeforeCpuAddress(uint32_t *addr)
601
602
603
{
return Symbols_GetBeforeAddress(CpuSymbolsList, addr);
}
604
const char* Symbols_GetBeforeDspAddress(uint32_t *addr)
605
606
607
608
{
return Symbols_GetBeforeAddress(DspSymbolsList, addr);
}
609
/**
610
* Binary search symbol by address in given sorted list.
611
* Return symbol index if address matches, -1 otherwise.
612
613
614
*
* Performance critical, called on every instruction
* when profiling is enabled.
615
*/
616
static int Symbols_SearchByAddress(symbol_t* entries, int count, uint32_t addr)
617
618
619
{
/* left, right, middle */
int l, r, m;
620
uint32_t curr;
621
622
623
/* bisect */
l = 0;
624
r = count - 1;
625
626
627
628
do {
m = (l+r) >> 1;
curr = entries[m].address;
if (curr == addr) {
629
return m;
630
631
632
633
634
635
636
}
if (curr > addr) {
r = m-1;
} else {
l = m+1;
}
} while (l <= r);
637
return -1;
638
639
640
}
/**
641
642
* Search symbol in given list by type & address.
* Return symbol name if there's a match, NULL otherwise.
643
* Code symbols will be matched before other symbol types.
644
* Returned name is valid only until next Symbols_* function call.
645
*/
646
static const char* Symbols_GetByAddress(symbol_list_t* list, uint32_t addr, symtype_t type)
647
{
648
if (!(list && list->addresses)) {
649
650
return NULL;
}
651
if (type & SYMTYPE_CODE) {
652
653
654
655
656
int i = Symbols_SearchByAddress(list->addresses, list->codecount, addr);
if (i >= 0) {
return list->addresses[i].name;
}
}
657
if (type & ~SYMTYPE_CODE) {
658
659
660
661
662
663
int i = Symbols_SearchByAddress(list->addresses + list->codecount, list->datacount, addr);
if (i >= 0) {
return list->addresses[list->codecount + i].name;
}
}
return NULL;
664
}
665
const char* Symbols_GetByCpuAddress(uint32_t addr, symtype_t type)
666
{
667
return Symbols_GetByAddress(CpuSymbolsList, addr, type);
668
}
669
const char* Symbols_GetByDspAddress(uint32_t addr, symtype_t type)
670
{
671
return Symbols_GetByAddress(DspSymbolsList, addr, type);
672
673
}
674
/**
675
* Search given list for code symbol by address.
676
677
* Return symbol index if address matches, -1 otherwise.
*/
678
static int Symbols_GetCodeIndex(symbol_list_t* list, uint32_t addr)
679
680
681
682
683
684
{
if (!list) {
return -1;
}
return Symbols_SearchByAddress(list->addresses, list->codecount, addr);
}
685
int Symbols_GetCpuCodeIndex(uint32_t addr)
686
{
687
688
return Symbols_GetCodeIndex(CpuSymbolsList, addr);
}
689
int Symbols_GetDspCodeIndex(uint32_t addr)
690
691
{
return Symbols_GetCodeIndex(DspSymbolsList, addr);
692
693
694
}
/**
695
* Return how many TEXT symbols are loaded/available
696
*/
697
int Symbols_CpuCodeCount(void)
698
{
699
return (CpuSymbolsList ? CpuSymbolsList->codecount : 0);
700
}
701
int Symbols_DspCodeCount(void)
702
{
703
return (DspSymbolsList ? DspSymbolsList->codecount : 0);
704
}
705
706
/* ---------------- symbol showing ------------------ */
707
708
/**
709
710
* Show symbols matching (optional) 'find' string from given list,
* using paging.
711
*/
712
static void Symbols_Show(symbol_list_t* list, const char *sortcmd, const char *find)
713
{
714
symbol_t *entry, *entries;
715
const char *symtype, *sorttype;
716
int i, row, rows, count, matches;
717
char symchar;
718
char line[80];
719
720
721
722
723
if (!list) {
fprintf(stderr, "No symbols!\n");
return;
}
724
725
726
if (strcmp("code", sortcmd) == 0) {
sorttype = "address";
727
entries = list->addresses;
728
count = list->codecount;
729
symtype = " TEXT/WEAK";
730
731
732
733
734
} else if (strcmp("data", sortcmd) == 0) {
sorttype = "address";
entries = list->addresses + list->codecount;
count = list->datacount;
symtype = " DATA/BSS/ABS";
735
} else {
736
sorttype = "name";
737
entries = list->names;
738
739
count = list->namecount;
symtype = "";
740
}
741
rows = DebugUI_GetPageLines(ConfigureParams.Debugger.nSymbolLines, 20);
742
row = matches = 0;
743
744
for (entry = entries, i = 0; i < count; i++, entry++) {
745
746
747
748
749
if (find && !strstr(entry->name, find)) {
continue;
}
matches++;
750
symchar = symbol_char(entry->type);
751
752
fprintf(stderr, "0x%08x %c %s\n",
entry->address, symchar, entry->name);
753
754
755
756
row++;
if (row >= rows) {
row = 0;
757
fprintf(stderr, "--- q to exit listing, just enter to continue --- ");
758
759
if (fgets(line, sizeof(line), stdin) == NULL ||
toupper(line[0]) == 'Q') {
760
break;
761
762
}
}
763
}
764
765
fprintf(stderr, "%d %s%s symbols (of %d) sorted by %s.\n",
matches, (list == CpuSymbolsList ? "CPU" : "DSP"),
766
symtype, count, sorttype);
767
768
}
769
770
771
/* ---------------- binary load handling ------------------ */
/**
772
773
* If autoloading is enabled and program symbols are present,
* remove them along with program path.
774
775
776
*
* Called on GEMDOS reset and when program terminates
* (unless terminated with Ptermres()).
777
778
779
780
781
782
783
*/
void Symbols_RemoveCurrentProgram(void)
{
if (CurrentProgramPath) {
free(CurrentProgramPath);
CurrentProgramPath = NULL;
784
if (CpuSymbolsList && CpuSymbolsAreFor == SYMBOLS_FOR_PROGRAM &&
785
ConfigureParams.Debugger.bSymbolsAutoLoad) {
786
Symbols_Free(CpuSymbolsList);
787
fprintf(stderr, "Program exit, removing its symbols.\n");
788
CpuSymbolsAreFor = SYMBOLS_FOR_NONE;
789
790
791
CpuSymbolsList = NULL;
}
}
792
AutoLoadFailed = false;
793
794
795
}
/**
796
797
* Call Symbols_RemoveCurrentProgram() and
* set last opened program path.
798
799
*
* Called on first Fopen() after Pexec().
800
*/
801
void Symbols_ChangeCurrentProgram(const char *path)
802
{
803
if (Opt_IsAtariProgram(path)) {
804
Symbols_RemoveCurrentProgram();
805
806
807
808
CurrentProgramPath = strdup(path);
}
}
809
810
811
812
813
814
815
816
/*
* Show currently set program path
*/
void Symbols_ShowCurrentProgramPath(FILE *fp)
{
if (CurrentProgramPath) {
fprintf(fp, "Current program path: %s\n", CurrentProgramPath);
} else {
817
fputs("No program has been loaded (through GEMDOS HD).\n", fp);
818
819
820
}
}
821
/**
822
823
824
* Autoload helper. Given the base file name with .XXX extension,
* if there's another file with .sym extension, load symbols from it,
* and return them.
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
*
* Assumes all (relevant) sections use the same load address.
*/
static symbol_list_t *loadSymFile(const char *path, symtype_t symtype,
uint32_t loadaddr, uint32_t maxaddr)
{
int len = strlen(path);
char symfile[len+1];
if (len <= 3 || path[len-4] != '.') {
return NULL;
}
strcpy(symfile, path);
strcpy(symfile + len - 3, "sym");
fprintf(stderr, "Checking: %s\n", symfile);
if (!File_Exists(symfile)) {
return NULL;
}
uint32_t offsets[3] = { loadaddr, loadaddr, loadaddr };
return Symbols_Load(symfile, offsets, maxaddr, symtype);
}
849
/**
850
* Load symbols for last opened program when symbol autoloading is enabled.
851
852
853
854
855
*
* If there's file with same name as the program, but with '.sym'
* extension, that overrides / is loaded instead of the symbol table
* in the program.
*
856
* Called when debugger is invoked.
857
858
859
*/
void Symbols_LoadCurrentProgram(void)
{
860
861
862
if (!ConfigureParams.Debugger.bSymbolsAutoLoad) {
return;
}
863
864
/* program path missing or previous load failed? */
if (!CurrentProgramPath || AutoLoadFailed) {
865
866
return;
}
867
/* do not override manually loaded symbols, or
868
869
* load new symbols if previous program did not terminate.
* Autoloaded TOS symbols could be overridden though
870
*/
871
if (CpuSymbolsList && CpuSymbolsAreFor != SYMBOLS_FOR_TOS) {
872
return;
873
}
874
875
876
877
878
879
880
881
882
uint32_t loadaddr = DebugInfo_GetTEXT();
uint32_t maxaddr = DebugInfo_GetTEXTEnd();
symbol_list_t *symbols;
symbols = loadSymFile(CurrentProgramPath, SYMTYPE_CODE, loadaddr, maxaddr);
if (symbols) {
fprintf(stderr, "Symbols override loaded for: %s\n", CurrentProgramPath);
} else {
883
884
symbols = Symbols_Load(CurrentProgramPath, NULL, 0,
SYMTYPE_CODE);
885
886
}
if (!symbols) {
887
AutoLoadFailed = true;
888
return;
889
}
890
891
892
AutoLoadFailed = false;
CpuSymbolsAreFor = SYMBOLS_FOR_PROGRAM;
893
CpuSymbolsList = symbols;
894
895
}
896
897
898
899
900
901
902
903
904
905
906
/**
* If autoloading enabled and no symbols are present, load symbols
* for <tos>.img file from <tos>.sym file, if one exists.
*
* Called whenever TOS is loaded.
*/
void Symbols_LoadTOS(const char *path, uint32_t maxaddr)
{
if (!ConfigureParams.Debugger.bSymbolsAutoLoad) {
return;
}
907
908
/* do not override manually loaded symbols */
if (CpuSymbolsList && CpuSymbolsAreFor == SYMBOLS_FOR_USER) {
909
910
911
912
913
return;
}
CpuSymbolsList = loadSymFile(path, SYMTYPE_ALL, 0, maxaddr);
if (CpuSymbolsList) {
fprintf(stderr, "Loaded symbols for TOS: %s\n", path);
914
CpuSymbolsAreFor = SYMBOLS_FOR_TOS;
915
916
917
}
}
918
919
/* ---------------- command parsing ------------------ */
920
921
922
923
924
925
926
927
/**
* Readline match callback to list symbols subcommands.
* STATE = 0 -> different text from previous one.
* Return next match or NULL if no matches.
*/
char *Symbols_MatchCommand(const char *text, int state)
{
static const char* subs[] = {
928
"autoload", "code", "data", "free", "match", "name", "prg"
929
};
930
931
932
933
934
char *ret = DebugUI_MatchHelper(subs, ARRAY_SIZE(subs), text, state);
if (ret) {
return ret;
}
return Symbols_MatchCpuAddress(text, state);
935
936
}
937
const char Symbols_Description[] =
938
"<code|data|name> [find] -- list symbols containing 'find'\n"
939
"\tsymbols <prg|free> -- load/free symbols\n"
940
941
"\t <filename> [<T offset> [<D offset> <B offset>]]\n"
"\tsymbols <autoload|match> -- toggle symbol options\n"
942
943
944
"\n"
"\t'name' command lists the currently loaded symbols, sorted by name.\n"
"\t'code' and 'data' commands list them sorted by address; 'code' lists\n"
945
946
"\tonly TEXT/WEAK symbols, 'data' lists DATA/BSS/ABS symbols. If 'find'\n"
"\tis given, only symbols with that substring are listed.\n"
947
948
"\n"
"\tBy default, symbols are loaded from the currently executing program's\n"
949
950
"\tbinary when entering the debugger, IF program is started through\n"
"\tGEMDOS HD, and they're freed when that program terminates.\n"
951
"\n"
952
"\tThat corresponds to 'prg' command which loads (DRI/GST or a.out\n"
953
954
"\tformat) symbol table from the last program executed through\n"
"\tthe GEMDOS HD emulation.\n"
955
"\n"
956
"\t'free' command removes the loaded symbols.\n"
957
"\n"
958
"\tIf program lacks symbols, or it's not run through the GEMDOS HD\n"
959
960
961
"\temulation, user can ask symbols to be loaded from a file that's\n"
"\tan unstripped version of the binary. Or from an ASCII symbols file\n"
"\tproduced by the 'nm' and (Hatari) 'gst2ascii' tools.\n"
962
"\n"
963
964
965
"\tWith ASCII symbols files, given non-zero offset(s) are added to\n"
"\tthe text (T), data (D) and BSS (B) symbols. Typically one uses\n"
"\tTEXT variable, sometimes also DATA & BSS, variables for this.\n"
966
"\n"
967
968
969
970
971
"\t'autoload [on|off]' command toggle/set whether debugger will load\n"
"\tsymbols for currently executing (GEMDOS HD) program automatically\n"
"\ton entering the debugger (i.e. replace earlier loaded symbols),\n"
"\tand free them when program terminates. It needs to be disabled\n"
"\tto debug memory-resident programs used by other programs.\n"
972
"\n"
973
974
975
"\t'match' command toggles whether TAB completion matches all symbols,\n"
"\tor only symbol types that should be relevant for given command.";
976
977
/**
978
* Handle debugger 'symbols' command and its arguments
979
*/
980
int Symbols_Command(int nArgc, char *psArgs[])
981
{
982
enum { TYPE_CPU, TYPE_DSP } listtype;
983
uint32_t offsets[3], maxaddr;
984
symbol_list_t *list;
985
const char *file;
986
int i;
987
988
989
990
if (strcmp("dspsymbols", psArgs[0]) == 0) {
listtype = TYPE_DSP;
maxaddr = 0xFFFF;
991
} else {
992
listtype = TYPE_CPU;
993
994
995
996
if ( ConfigureParams.System.bAddressSpace24 )
maxaddr = 0x00FFFFFF;
else
maxaddr = 0xFFFFFFFF;
997
}
998
999
1000
if (nArgc < 2) {
file = "name";
} else {