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