1 /* lknoice.c */
2
3 /*
4 * Copyright (C) 1989-2009 Alan R. Baldwin
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 *
20 * Alan R. Baldwin
21 * 721 Berkeley St.
22 * Kent, Ohio 44240
23 *
24 *
25 * Extensions to produce NoICE debug files
26 *
27 * 31-Oct-1997 by John Hartman
28 * 30-Jan-98 JLH add page to DefineNoICE for 8051
29 * 2-Feb-98 JLH Allow optional .nest on local vars - C scoping rules...
30 * 27-May-01 ARB Updated for ASxxxx V4
31 */
32
33 #include "aslink.h"
34
35
36 #if NOICE
37
38 /*Module lknoice.c
39 *
40 * The module lknoice.c contains the functions
41 * required to create a NoICE debug file.
42 *
43 * lknoice.c contains the following functions:
44 * VOID NoICEfopen()
45 * VOID NoICEmagic()
46 * VOID DefineNoICE()
47 * VOID DefineGlobal()
48 * VOID DefineScoped()
49 * VOID DefineFile()
50 * VOID DefineFunction()
51 * VOID DefineStaticFunction()
52 * VOID DefineEndFunction()
53 * VOID DefineLine()
54 * VOID PagedAddress()
55 *
56 * lknoice.c contains these local variables:
57 * struct noicebn *noicebnp pointer to linked structure of
58 * ';!FILE' specifications
59 * char currentFile[] file being processed
60 * char currentFunction[] function being processed
61 */
62
63 struct noicefn {
64 struct noicefn *n_np; /* noicefn link */
65 char * n_id; /* file name */
66 };
67
68 static struct noicefn *noicefnp = NULL;
69
70 static char currentFile[NCPS];
71 static char currentFunction[NCPS];
72
73
74 /*)Function VOID NoICEfopen()
75 *
76 * The function NoICEfopen() opens the NoICE output file
77 * and sets the map flag, mflag, to create a map file.
78 * NoICE processing is performed during map generation.
79 *
80 * local variables:
81 * none
82 *
83 * global variables:
84 * int jflag NoICE Debug flag
85 * FILE * jfp NoICE Debug File handle
86 * struct lfile *linkp Pointer to the Linker output file name
87 * int mflag Map output flag
88 *
89 * functions called:
90 * FILE * afile() lkmain.c
91 * VOID lkexit() lkmain.c
92 *
93 * side effects:
94 * The NoICE output file is opened.
95 * Failure to open the file will
96 * terminate the linker.
97 */
98
NoICEfopen(void)99 VOID NoICEfopen(void)
100 {
101 if (jflag) {
102 jfp = afile(linkp->f_idp, "noi", 1);
103 if (jfp == NULL) {
104 lkexit(1);
105 }
106 mflag = 1;
107 }
108 }
109
110
111 /*)Function VOID NoICEmagic()
112 *
113 * The function NoICEmagic() passes any "magic Comments"
114 * to the NoICE output file. Magic comments are those
115 * beginning with ";!". Also a linked list of file names
116 * specified in ";!FILE" magic comments is created. These
117 * file names are used to verify that symbols in the
118 * ASxxxx .rel files of the form str1.str2 are NoICE symbols.
119 *
120 * local variables:
121 * char id[] id string
122 * struct noicefn * np pointer to new structure
123 * char * p1 temporary string pointer
124 * char * p2 temporary string pointer
125 * struct noicefn * tnp temporary pointer to noicefn structure
126 *
127 * global variables:
128 * char * ip position into the current
129 * input text line
130 * FILE * jfp NoICE Debug File handle
131 *
132 * functions called:
133 * VOID getid() lklex.c
134 * VOID * new() lksym.c
135 * int fprintf() c_library
136 * char * strrchr() c_library
137 * char * strsto() lksym.c
138 * int symeq() lksym.c
139 *
140 * side effects:
141 * The NoICE "magic comments" are passed
142 * to the output file. A list of assembler
143 * file names is created.
144 */
145
NoICEmagic(void)146 VOID NoICEmagic(void)
147 {
148 char id[NCPS];
149 char *p1, *p2;
150 struct noicefn *np, *tnp;
151
152 /*
153 * Pass any "magic comments" to NoICE output
154 */
155 if ((ip[0] == ';') && (ip[1] == '!')) {
156 if (jfp) {
157 fprintf(jfp, "%s\n", &ip[2]);
158 }
159 if (pass == 0) {
160 getid(id, -1);
161 if (symeq(id, ";!FILE", 1)) {
162 getid(id, -1);
163 /*
164 * The name starts after the last
165 * '/' (Unices) or
166 * ':' or '\' (DOS)
167 *
168 * and ends at the last
169 * separator 'FSEPX'
170 */
171 p1 = id;
172 if ((p2 = strrchr(p1, '\\')) != NULL) p1 = ++p2;
173 if ((p2 = strrchr(p1, '/')) != NULL) p1 = ++p2;
174 if ((p2 = strrchr(p1, ':')) != NULL) p1 = ++p2;
175 if ((p2 = strrchr(p1, FSEPX)) != NULL) *p2 = 0;
176
177 np = (struct noicefn *) new (sizeof(struct noicefn));
178 if (noicefnp == NULL) {
179 noicefnp = np;
180 } else {
181 tnp = noicefnp;
182 while (tnp->n_np)
183 tnp = tnp->n_np;
184 tnp->n_np = np;
185 }
186 np->n_id = strsto(p1);
187 }
188 }
189 }
190 }
191
192
193 /*)Function VOID DefineNoICE()
194 *
195 * char * name pointer to the symbol string
196 * a_uint value value of symbol
197 * struct bank * yp pointer to associated bank
198 *
199 * The function DefineNoICE() processes the symbols into
200 * NoICE commands for inclusion in the NoICE output file.
201 *
202 * The function is called from lstarea in lklist.c
203 * for each symbol.
204 *
205 * local variables:
206 * int j parsed argument count
207 * int k parsed argument count
208 * int level function level
209 * char token1[] parsed string
210 * char token2[] parsed string
211 * char token2[] parsed string
212 * char sep1 parsed character
213 * char sep2 parsed character
214 * struct noicefn * tnp temporary pointer to noicefn structure
215 *
216 * global variables:
217 * FILE * jfp NoICE Debug File handle
218 *
219 * functions called:
220 * VOID DefineFile() lknoice.c
221 * VOID DefineFunction() lknoice.c
222 * VOID DefineStaticFunction() lknoice.c
223 * VOID DefineEndFunction() lknoice.c
224 * VOID DefineScoped() lknoice.c
225 * VOID DefineLine() lknoice.c
226 * VOID DefineGlobal() lknoice.c
227 * VOID PagedAddress() lknoice.c
228 * int sprintf() c_library
229 * int sscanf() c_library
230 * int symeq() lksym.c
231 *
232 * side effects:
233 * NoICE debug commands are placed
234 * into the output file.
235 */
236
DefineNoICE(char * name,a_uint value,struct bank * yp)237 void DefineNoICE( char *name, a_uint value, struct bank *yp )
238 {
239 char token1[NCPS]; /* parse for file.function.symbol */
240 char token2[NCPS];
241 char token3[NCPS];
242 char sep1, sep2;
243 int j, k, level;
244 struct noicefn *np;
245
246 /* no output if file is not open */
247 if (jfp == NULL) return;
248
249 j = sscanf( name, "%[^.]%c%[^.]%c%s", token1, &sep1, token2, &sep2, token3 );
250 if (j > 1) {
251 /* verify that first token is a file name */
252 k = 1;
253 np = noicefnp;
254 while (np != NULL) {
255 if (symeq(token1, np->n_id, 1)) {
256 k = j;
257 break;
258 }
259 np = np->n_np;
260 }
261 j = k;
262 }
263
264 switch (j)
265 {
266 /* file.function.symbol, or file.function..SPECIAL */
267 case 5:
268 DefineFile( token1, 0, NULL );
269 if (token3[0] == '.')
270 {
271 if (symeq( token3, ".FN", 1 ) != 0)
272 {
273 /* Global function */
274 DefineFunction( token2, value, yp );
275 }
276 else if (symeq( token3, ".SFN", 1 ) != 0)
277 {
278 /* Static (file-scope) function */
279 DefineStaticFunction( token2, value, yp );
280 }
281 else if (symeq( token3, ".EFN", 1 ) != 0)
282 {
283 /* End of function */
284 DefineEndFunction( value, yp );
285 }
286 }
287 else
288 {
289 /* Function-scope var. */
290 DefineFunction( token2, 0, NULL );
291
292 /* Look for optional level integer */
293 j = sscanf( token3, "%[^.]%c%u", token1, &sep1, &level );
294 if ((j == 3) && (level != 0))
295 {
296 sprintf( &token1[ strlen(token1) ], "_%u", level );
297 }
298 DefineScoped( token1, value, yp );
299 }
300 break;
301
302 /* either file.symbol or file.line# */
303 case 3:
304 DefineFile( token1, 0, NULL );
305 if ((token2[0] >= '0') && (token2[0] <= '9'))
306 {
307 /* Line number */
308 DefineLine( token2, value, yp );
309 }
310 else
311 {
312 /* File-scope symbol. (Kill any function) */
313 DefineEndFunction( 0, NULL );
314 DefineScoped( token2, value, yp );
315 }
316 break;
317
318 /* NoICE file.func. is illegal */
319 case 4:
320
321 /* NoICE symbol. is illegal */
322 case 2:
323
324 /* just a symbol */
325 case 1:
326
327 /* NoICE .symbol is illegal */
328 case 0:
329 default:
330 DefineGlobal( name, value, yp );
331 break;
332 }
333 }
334
335
336 /*)Function VOID DefineGlobal()
337 *
338 * char * name pointer to the symbol string
339 * a_uint value value of symbol
340 * struct bank * yp pointer to associated bank
341 *
342 * The function DefineGlobal() places a DEF statement
343 * in the .noi debug file for the global symbol.
344 *
345 * local variables:
346 * none
347 *
348 * global variables:
349 * FILE * jfp NoICE Debug File handle
350 *
351 * functions called:
352 * int fprintf() c_library
353 * VOID PagedAddress() lknoice.c
354 *
355 * side effects:
356 * A global symbol definition is
357 * placed in the .noi debug file.
358 */
359
DefineGlobal(char * name,a_uint value,struct bank * yp)360 void DefineGlobal( char *name, a_uint value, struct bank *yp )
361 {
362 fprintf( jfp, "DEF %s ", name );
363 PagedAddress( value, yp );
364 }
365
366
367 /*)Function VOID DefineScoped()
368 *
369 * char * name pointer to the symbol string
370 * a_uint value value of symbol
371 * struct bank * yp pointer to associated bank
372 *
373 * The function DefineScoped() places a DEFS statement
374 * in the .noi debug file for the scoped symbol.
375 *
376 * local variables:
377 * none
378 *
379 * global variables:
380 * FILE * jfp NoICE Debug File handle
381 *
382 * functions called:
383 * int fprintf() c_library
384 * VOID PagedAddress() lknoice.c
385 *
386 * side effects:
387 * A scoped symbol definition is
388 * placed in the .noi debug file.
389 */
390
DefineScoped(char * name,a_uint value,struct bank * yp)391 void DefineScoped( char *name, a_uint value, struct bank *yp )
392 {
393 fprintf( jfp, "DEFS %s ", name );
394 PagedAddress( value, yp );
395 }
396
397
398 /*)Function VOID DefineFile()
399 *
400 * char * name pointer to the symbol string
401 * a_uint value value of symbol
402 * struct bank * yp pointer to associated bank
403 *
404 * The function DefineFile() places a FILE statement
405 * in the .noi debug file for the processed file.
406 *
407 * local variables:
408 * none
409 *
410 * global variables:
411 * FILE * jfp NoICE Debug File handle
412 *
413 * functions called:
414 * int fprintf() c_library
415 * VOID PagedAddress() lknoice.c
416 * char * strcpy() c_library
417 * int symeq() lksym.c
418 *
419 * side effects:
420 * A file name definition is
421 * placed in the .noi debug file.
422 */
423
DefineFile(char * name,a_uint value,struct bank * yp)424 void DefineFile( char *name, a_uint value, struct bank *yp )
425 {
426 if (symeq( name, currentFile, 1 ) == 0)
427 {
428 strcpy( currentFile, name );
429 if (value != 0)
430 {
431 fprintf( jfp, "FILE %s ", name );
432 PagedAddress( value, yp );
433 }
434 else
435 {
436 fprintf( jfp, "FILE %s\n", name );
437 }
438 }
439 }
440
441
442 /*)Function VOID DefineFunction()
443 *
444 * char * name pointer to the symbol string
445 * a_uint value value of symbol
446 * struct bank * yp pointer to associated bank
447 *
448 * The function DefineFunction() places a FUNC statement
449 * in the .noi debug file for the processed symbol. If
450 * a vaulue is present then a preceeding DEF statement is
451 * also placed in the .noi debug file.
452 *
453 * local variables:
454 * none
455 *
456 * global variables:
457 * FILE * jfp NoICE Debug File handle
458 *
459 * functions called:
460 * int fprintf() c_library
461 * VOID PagedAddress() lknoice.c
462 * char * strcpy() c_library
463 * int symeq() lksym.c
464 *
465 * side effects:
466 * A function definition is
467 * placed in the .noi debug file.
468 */
469
DefineFunction(char * name,a_uint value,struct bank * yp)470 void DefineFunction( char *name, a_uint value, struct bank *yp )
471 {
472 if (symeq( name, currentFunction, 1 ) == 0)
473 {
474 strcpy( currentFunction, name );
475 if (value != 0)
476 {
477 fprintf( jfp, "DEF %s ", name );
478 PagedAddress( value, yp );
479 fprintf( jfp, "FUNC %s ", name );
480 PagedAddress( value, yp );
481 }
482 else
483 {
484 fprintf( jfp, "FUNC %s\n", name );
485 }
486 }
487 }
488
489
490 /*)Function VOID DefineStaticFunction()
491 *
492 * char * name pointer to the symbol string
493 * a_uint value value of symbol
494 * struct bank * yp pointer to associated bank
495 *
496 * The function DefineStaticFunction() places a SFUNC statement
497 * in the .noi debug file for the processed file. If
498 * a value is present then a preceeding DEFS statement is
499 * also placed in the .noi debug file.
500 *
501 * local variables:
502 * none
503 *
504 * global variables:
505 * FILE * jfp NoICE Debug File handle
506 *
507 * functions called:
508 * int fprintf() c_library
509 * VOID PagedAddress() lknoice.c
510 * char * strcpy() c_library
511 * int symeq() lksym.c
512 *
513 * side effects:
514 * A static function definition is
515 * placed in the .noi debug file.
516 */
517
DefineStaticFunction(char * name,a_uint value,struct bank * yp)518 void DefineStaticFunction( char *name, a_uint value, struct bank *yp )
519 {
520 if (symeq( name, currentFunction, 1 ) == 0)
521 {
522 strcpy( currentFunction, name );
523 if (value != 0)
524 {
525 fprintf( jfp, "DEFS %s ", name );
526 PagedAddress( value, yp );
527 fprintf( jfp, "SFUNC %s ", name );
528 PagedAddress( value, yp );
529 }
530 else
531 {
532 fprintf( jfp, "SFUNC %s\n", name );
533 }
534 }
535 }
536
537
538 /*)Function VOID DefineEndFunction()
539 *
540 * char * name pointer to the symbol string
541 * a_uint value value of symbol
542 * struct bank * yp pointer to associated bank
543 *
544 * The function DefineEndFunction() places an ENDF statement
545 * in the .noi debug file for the processed file.
546 *
547 * local variables:
548 * none
549 *
550 * global variables:
551 * FILE * jfp NoICE Debug File handle
552 *
553 * functions called:
554 * int fprintf() c_library
555 * VOID PagedAddress() lknoice.c
556 * char * strcpy() c_library
557 * int symeq() lksym.c
558 *
559 * side effects:
560 * An end function definition is
561 * placed in the .noi debug file.
562 */
563
DefineEndFunction(a_uint value,struct bank * yp)564 void DefineEndFunction( a_uint value, struct bank *yp )
565 {
566 if (currentFunction[0] != 0)
567 {
568 if (value != 0)
569 {
570 fprintf( jfp, "ENDF " );
571 PagedAddress( value, yp );
572 }
573 else
574 {
575 fprintf( jfp, "ENDF\n" );
576 }
577
578 currentFunction[0] = 0;
579 }
580 }
581
582
583 /*)Function VOID DefineLine()
584 *
585 * char * name pointer to the symbol string
586 * a_uint value value of symbol
587 * struct bank * yp pointer to associated bank
588 *
589 * The function DefineLine() places a LINE statement
590 * in the .noi debug file for the processed file.
591 *
592 * local variables:
593 * int indigit converted digit
594 * int lineNumber converted line number
595 *
596 * global variables:
597 * FILE * jfp NoICE Debug File handle
598 *
599 * functions called:
600 * int fprintf() c_library
601 * VOID PagedAddress() lknoice.c
602 * int digit() lkeval.c
603 *
604 * side effects:
605 * A Line definition is
606 * placed in the .noi debug file.
607 */
608
DefineLine(char * lineString,a_uint value,struct bank * yp)609 void DefineLine( char *lineString, a_uint value, struct bank *yp )
610 {
611 int indigit, lineNumber;
612
613 lineNumber = 0;
614 while( (indigit=digit( *lineString++, 10 )) >= 0)
615 {
616 lineNumber = 10*lineNumber + indigit;
617 }
618 fprintf( jfp, "LINE %u ", lineNumber );
619 PagedAddress( value, yp );
620 }
621
622
623 /*)Function VOID PagedAddress()
624 *
625 * a_uint value value of symbol
626 * struct bank * yp pointer to associated bank
627 *
628 * The function PagedAddress() places the value
629 * in the .noi debug file for the processed value.
630 * If the current bank is "mapped" then the page
631 * number preceeds the value as xx:.
632 *
633 * local variables:
634 * none
635 *
636 * global variables:
637 * FILE * jfp NoICE Debug File handle
638 *
639 * functions called:
640 * int fprintf() c_library
641 *
642 * side effects:
643 * A value is appended to the current
644 * line placed in the .noi debug file.
645 */
646
PagedAddress(a_uint value,struct bank * yp)647 void PagedAddress( a_uint value, struct bank *yp )
648 {
649 if (yp->b_flag & B_MAP) {
650 fprintf( jfp, "%X:0x%X\n", yp->b_map, value );
651 } else {
652 fprintf( jfp, "0x%X\n", value );
653 }
654 }
655
656 #endif
657