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