1 /* ======================================================================== */
2 /* Routines for managing source code in the debugger. */
3 /* ======================================================================== */
4
5 #include "config.h"
6 #include "lzoe/lzoe.h"
7 #include "file/file.h"
8 #include "source.h"
9 #include "debug/debug_tag.h"
10 #include "asm/typetags.h"
11
12 typedef struct smapping
13 {
14 unsigned file : 12; /* up to 4095 files */
15 unsigned line : 20; /* up to 1M lines / file */
16 unsigned flag : 8; /* up to 8 flag bits */
17 unsigned list_line : 24; /* up to 16M lines in listing */
18 } smapping;
19
20 #define MAX_SOURCE_FILES (4095)
21
22 smapping smap_tbl[65536];
23
24 source_file_info *source_file;
25 int source_files;
26 int sf_alloc = 0;
27 smap_mode smode = SMAP_SMART;
28 path_t *as1600_search_path;
29 int listing_handle;
30
31 #define FL_PREFER_LISTING (1)
32 #define SOURCEOFFSET (32) /* same meaning as in assembler */
33
34 void set_source_map_mode(smap_mode mode);
35
36 /* ======================================================================== */
37 /* GET_FILE_HANDLE -- Get the text_file handle for a filename. */
38 /* ======================================================================== */
get_file_handle(const char * name)39 LOCAL int get_file_handle(const char *name)
40 {
41 LZFILE *f;
42 int i;
43
44 /* -------------------------------------------------------------------- */
45 /* First see if we've already got this file. */
46 /* -------------------------------------------------------------------- */
47 for (i = 0; i < source_files; i++)
48 if (!strcmp(source_file[i].name, name))
49 return i + 1;
50
51 /* -------------------------------------------------------------------- */
52 /* Only allow up to MAX_SOURCE_FILES files for now. */
53 /* -------------------------------------------------------------------- */
54 if (source_files == MAX_SOURCE_FILES)
55 return 0;
56
57 /* -------------------------------------------------------------------- */
58 /* Next see if we can open the file. */
59 /* -------------------------------------------------------------------- */
60 f = path_fopen(as1600_search_path, name, "rb");
61
62 if (!f)
63 return 0;
64
65 /* -------------------------------------------------------------------- */
66 /* Now allocate a slot for it and populate it. */
67 /* -------------------------------------------------------------------- */
68 if (source_files >= sf_alloc)
69 {
70 sf_alloc += 16;
71 source_file = (source_file_info *)
72 realloc(source_file, sf_alloc *
73 sizeof(source_file_info));
74 }
75
76 jzp_printf("Reading %s... ", name);
77
78 source_file[source_files].name = strdup(name);
79 source_file[source_files].text = load_text_file(f, 8);
80
81 if (!source_file[source_files].text)
82 {
83 jzp_printf("failed\n"); jzp_flush();
84 CONDFREE(source_file[source_files].name);
85 return 0;
86 }
87
88 jzp_printf("%d lines.\n", source_file[source_files].text->lines);
89 jzp_flush();
90 lzoe_fclose(f);
91
92 return ++source_files;
93 }
94
95
96
97 /* ======================================================================== */
98 /* PROCESS_SOURCE_MAP -- Process a source-map file */
99 /* */
100 /* Directive lines: */
101 /* CWD <string> Source directory where AS1600 ran */
102 /* PATH <string> Adds <string> to AS1600 search path */
103 /* LISTING <string> Indicates <string> is the AS1600 listing file */
104 /* FILE <string> Sets <string> as the current source file */
105 /* */
106 /* Mapping lines: */
107 /* <addr> <addr> <flags> <source_line> <listing_line> */
108 /* */
109 /* ======================================================================== */
process_source_map(const char * fname)110 void process_source_map(const char *fname)
111 {
112 LZFILE *f;
113 char buf[2048], *s;
114 char *cwd = NULL;
115 int curr = 0;
116 uint32_t lo, hi, flags, src_line, list_line, addr, dflags;
117
118 if ((f = lzoe_fopen(fname, "r")) == NULL)
119 {
120 perror("fopen()");
121 fprintf(stderr, "Could not open '%s' for reading.\n", fname);
122 return;
123 }
124
125 while (lzoe_fgets(buf, sizeof(buf), f) != NULL)
126 {
127 if ((s = strchr(buf, '\012')) != NULL) *s = 0;
128 if ((s = strchr(buf, '\015')) != NULL) *s = 0;
129
130 /* ---------------------------------------------------------------- */
131 /* Keywords.... */
132 /* ---------------------------------------------------------------- */
133 if (!strncmp(buf, "CWD ", 4))
134 {
135 if (cwd) free(cwd);
136 cwd = strdup(buf + 4);
137 continue;
138 }
139
140 if (!strncmp(buf, "PATH ", 5))
141 {
142 s = make_absolute_path(cwd ? cwd : "", buf + 5);
143 as1600_search_path = append_path(as1600_search_path, s);
144 free(s);
145 continue;
146 }
147
148 if (!strncmp(buf, "LISTING ", 8))
149 {
150 listing_handle = get_file_handle(buf + 8);
151 continue;
152 }
153
154 if (!strncmp(buf, "FILE ", 5))
155 {
156 curr = get_file_handle(buf + 5);
157 continue;
158 }
159
160 /* ---------------------------------------------------------------- */
161 /* Ranges.... */
162 /* ---------------------------------------------------------------- */
163 if (sscanf(buf, "%x %x %x %d %d", &lo, &hi, &flags,
164 &src_line, &list_line) != 5
165 || lo > hi || lo > 0xFFFF)
166 {
167 fprintf(stderr, "Unhandled line in source map:\n>> %s\n", buf);
168 continue;
169 }
170
171 /* ---------------------------------------------------------------- */
172 /* Go mark the range in the source map table. */
173 /* ---------------------------------------------------------------- */
174 for (addr = lo; addr <= hi; addr++)
175 {
176 smap_tbl[addr].file = curr;
177 smap_tbl[addr].flag = flags;
178 smap_tbl[addr].line = src_line;
179 smap_tbl[addr].list_line = list_line;
180 }
181
182 /* ---------------------------------------------------------------- */
183 /* Update the memory attribute flags in the debugger. */
184 /* ---------------------------------------------------------------- */
185 dflags = ((flags & TYPE_CODE) ? DEBUG_MA_CODE : 0)
186 | ((flags & TYPE_DATA) ? DEBUG_MA_DATA : 0)
187 | ((flags & TYPE_DBDATA) ? DEBUG_MA_SDBD : 0)
188 | ((flags & TYPE_STRING) ? DEBUG_MA_DATA : 0);
189
190 debug_tag_range(lo, hi, dflags);
191
192 /* ---------------------------------------------------------------- */
193 /* Heuristic for "smart mode": If two consecutive ranges have */
194 /* the same file / line, but different listing line, then prefer */
195 /* the listing over the source when in "smart" mode. */
196 /* ---------------------------------------------------------------- */
197 if (lo > 0)
198 {
199 addr = lo;
200 while (smap_tbl[addr - 1].file == smap_tbl[lo].file &&
201 smap_tbl[addr - 1].line == smap_tbl[lo].line)
202 {
203 if (smap_tbl[addr - 1].list_line == smap_tbl[lo].list_line)
204 break;
205 addr--;
206 }
207
208 if (addr != lo)
209 {
210 while (addr <= hi)
211 smap_tbl[addr++].flag |= FL_PREFER_LISTING;
212 }
213 }
214 }
215
216 CONDFREE(cwd);
217 lzoe_fclose(f);
218
219 /* -------------------------------------------------------------------- */
220 /* Now step over the listing file, if there was one, and trim off */
221 /* the leading parts of the lines, keeping just the source. */
222 /* -------------------------------------------------------------------- */
223 if (listing_handle > 0)
224 {
225 uint32_t i, j, k;
226
227 text_file *text = source_file[listing_handle - 1].text;
228
229 for (i = 0; i != text->lines; i++)
230 {
231 k = text->line[i];
232
233 for (j = 0; j < SOURCEOFFSET; j++, k++)
234 {
235 if (text->body[k] == 0)
236 break;
237
238 if (text->body[k] == '\t')
239 j += (7 - (j & 7));
240 }
241
242 text->line[i] = k;
243 }
244 }
245 }
246
247 /* ======================================================================== */
248 /* SOURCE_FOR_ADDR -- Try to find code for this address, if any */
249 /* exists. Pull from source or listing based on */
250 /* the current mode. */
251 /* ======================================================================== */
source_for_addr(uint32_t addr)252 const char *source_for_addr(uint32_t addr)
253 {
254 int file = smap_tbl[addr].file - 1;
255 int sline = smap_tbl[addr].line - 1;
256 int lline = smap_tbl[addr].list_line - 1;
257 const char *src = NULL, *lst = NULL;
258
259 if (file >= 0 && sline >= 0 && sline < (int)source_file[file].text->lines)
260 src = &source_file[file].text->body[
261 source_file[file].text->line[sline]];
262
263 file = listing_handle - 1;
264 if (file >= 0 && lline >= 0 && lline < (int)source_file[file].text->lines)
265 lst = &source_file[file].text->body[
266 source_file[file].text->line[lline]];
267
268 if (smode == SMAP_SMART)
269 {
270 if (src && lst && (smap_tbl[addr].flag & FL_PREFER_LISTING) != 0)
271 return lst;
272
273 return src ? src : lst;
274 }
275
276 if (smode == SMAP_SOURCE)
277 return src;
278
279 return lst;
280 }
281
282 /* ======================================================================== */
283 /* FILE_LINE_FOR_ADDR -- Get the file and line associated with an addr. */
284 /* ======================================================================== */
file_line_for_addr(uint32_t addr,int * line)285 int file_line_for_addr(uint32_t addr, int *line)
286 {
287 int sfile = smap_tbl[addr].file - 1;
288 int sline = smap_tbl[addr].line - 1;
289 int lfile = listing_handle - 1;
290 int lline = smap_tbl[addr].list_line - 1;
291
292 if (sfile < 0 || sline >= (int)source_file[sfile].text->lines)
293 sline = -1;
294
295 if (lfile < 0 || lline >= (int)source_file[lfile].text->lines)
296 lline = -1;
297
298 if (smode == SMAP_SMART)
299 {
300 if (sline < 0 ||
301 (lline >= 0 && (smap_tbl[addr].flag & FL_PREFER_LISTING) != 0))
302 {
303 *line = lline;
304 return lfile;
305 }
306
307 *line = sline;
308 return sfile;
309 }
310
311 if (smode == SMAP_SOURCE)
312 {
313 *line = sline;
314 return sfile;
315 }
316
317 *line = lline;
318 return lfile;
319 }
320
321 /* ======================================================================== */
322 /* SOURCE_FOR_FILE_LINE -- Get the source line associated with the file */
323 /* handle and source line, if any. */
324 /* ======================================================================== */
source_for_file_line(int file,int line)325 const char *source_for_file_line(int file, int line)
326 {
327 if (file < 0 || file + 1 > source_files || line < 0)
328 return NULL;
329
330 if (line >= (int)source_file[file].text->lines)
331 return NULL;
332
333 return &source_file[file].text->body[source_file[file].text->line[line]];
334 }
335