1/*****************************************************************************/
2/* */
3/* dbginfo.c */
4/* */
5/* Handle the .dbg commands */
6/* */
7/* */
8/* */
9/* (C) 2000-2012, Ullrich von Bassewitz */
10/* Roemerstrasse 52 */
11/* D-70794 Filderstadt */
12/* EMail: uz@cc65.org */
13/* */
14/* */
15/* This software is provided 'as-is', without any expressed or implied */
16/* warranty. In no event will the authors be held liable for any damages */
17/* arising from the use of this software. */
18/* */
19/* Permission is granted to anyone to use this software for any purpose, */
20/* including commercial applications, and to alter it and redistribute it */
21/* freely, subject to the following restrictions: */
22/* */
23/* 1. The origin of this software must not be misrepresented; you must not */
24/* claim that you wrote the original software. If you use this software */
25/* in a product, an acknowledgment in the product documentation would be */
26/* appreciated but is not required. */
27/* 2. Altered source versions must be plainly marked as such, and must not */
28/* be misrepresented as being the original software. */
29/* 3. This notice may not be removed or altered from any source */
30/* distribution. */
31/* */
32/*****************************************************************************/
33
34
35
36#include <string.h>
37
38/* common */
39#include "chartype.h"
40#include "coll.h"
41#include "filepos.h"
42#include "hlldbgsym.h"
43#include "scopedefs.h"
44#include "strbuf.h"
45
46/* ca65 */
47#include "dbginfo.h"
48#include "error.h"
49#include "expr.h"
50#include "filetab.h"
51#include "global.h"
52#include "lineinfo.h"
53#include "objfile.h"
54#include "nexttok.h"
55#include "symentry.h"
56#include "symtab.h"
57
58
59
60/*****************************************************************************/
61/* Data */
62/*****************************************************************************/
63
64
65
66/* Structure used for a high level language function or symbol */
67typedef struct HLLDbgSym HLLDbgSym;
68struct HLLDbgSym {
69 unsigned Flags; /* See above */
70 unsigned Name; /* String id of name */
71 unsigned AsmName; /* String id of asm symbol name */
72 SymEntry* Sym; /* The assembler symbol */
73 int Offs; /* Offset if any */
74 unsigned Type; /* String id of type */
75 SymTable* Scope; /* Parent scope */
76 unsigned FuncId; /* Id of hll function if any */
77 FilePos Pos; /* Position of statement */
78};
79
80/* The current line info */
81static LineInfo* CurLineInfo = 0;
82
83/* List of high level language debug symbols */
84static Collection HLLDbgSyms = STATIC_COLLECTION_INITIALIZER;
85
86
87
88/*****************************************************************************/
89/* Code */
90/*****************************************************************************/
91
92
93
94static HLLDbgSym* NewHLLDbgSym (unsigned Flags, unsigned Name, unsigned Type)
95/* Allocate and return a new HLLDbgSym structure */
96{
97 /* Allocate memory */
98 HLLDbgSym* S = xmalloc (sizeof (*S));
99
100 /* Initialize the fields as necessary */
101 S->Flags = Flags;
102 S->Name = Name;
103 S->AsmName = EMPTY_STRING_ID;
104 S->Sym = 0;
105 S->Offs = 0;
106 S->Type = Type;
107 S->Scope = CurrentScope;
108 S->FuncId = ~0U;
109 S->Pos = CurTok.Pos;
110
111 /* Return the result */
112 return S;
113}
114
115
116
117static unsigned HexValue (char C)
118/* Convert the ascii representation of a hex nibble into the hex nibble */
119{
120 if (isdigit (C)) {
121 return C - '0';
122 } else if (islower (C)) {
123 return C - 'a' + 10;
124 } else {
125 return C - 'A' + 10;
126 }
127}
128
129
130
131static int ValidateType (StrBuf* Type)
132/* Check if the given type is valid and if so, return a string id for it. If
133** the type isn't valid, return -1. Type is overwritten when checking.
134*/
135{
136 unsigned I;
137 const char* A;
138 char* B;
139
140
141 /* The length must not be zero and divideable by two */
142 unsigned Length = SB_GetLen (Type);
143 if (Length < 2 || (Length & 0x01) != 0) {
144 ErrorSkip ("Type value has invalid length");
145 return -1;
146 }
147
148 /* The string must consist completely of hex digit chars */
149 A = SB_GetConstBuf (Type);
150 for (I = 0; I < Length; ++I) {
151 if (!IsXDigit (A[I])) {
152 ErrorSkip ("Type value contains invalid characters");
153 return -1;
154 }
155 }
156
157 /* Convert the type to binary */
158 B = SB_GetBuf (Type);
159 while (A < SB_GetConstBuf (Type) + Length) {
160 /* Since we know, there are only hex digits, there can't be any errors */
161 *B++ = (HexValue (A[0]) << 4) | HexValue (A[1]);
162 A += 2;
163 }
164 Type->Len = (Length /= 2);
165
166 /* Allocate the type and return it */
167 return GetStrBufId (Type);
168}
169
170
171
172void DbgInfoFile (void)
173/* Parse and handle FILE subcommand of the .dbg pseudo instruction */
174{
175 StrBuf Name = STATIC_STRBUF_INITIALIZER;
176 unsigned long Size;
177 unsigned long MTime;
178
179 /* Parameters are separated by a comma */
180 ConsumeComma ();
181
182 /* Name */
183 if (CurTok.Tok != TOK_STRCON) {
184 ErrorSkip ("String constant expected");
185 return;
186 }
187 SB_Copy (&Name, &CurTok.SVal);
188 NextTok ();
189
190 /* Comma expected */
191 ConsumeComma ();
192
193 /* Size */
194 Size = ConstExpression ();
195
196 /* Comma expected */
197 ConsumeComma ();
198
199 /* MTime */
200 MTime = ConstExpression ();
201
202 /* Insert the file into the table */
203 AddFile (&Name, FT_DBGINFO, Size, MTime);
204
205 /* Free memory used for Name */
206 SB_Done (&Name);
207}
208
209
210
211void DbgInfoFunc (void)
212/* Parse and handle func subcommand of the .dbg pseudo instruction */
213{
214 static const char* const StorageKeys[] = {
215 "EXTERN",
216 "STATIC",
217 };
218
219 unsigned Name;
220 int Type;
221 unsigned AsmName;
222 unsigned Flags;
223 HLLDbgSym* S;
224
225
226 /* Parameters are separated by a comma */
227 ConsumeComma ();
228
229 /* Name */
230 if (CurTok.Tok != TOK_STRCON) {
231 ErrorSkip ("String constant expected");
232 return;
233 }
234 Name = GetStrBufId (&CurTok.SVal);
235 NextTok ();
236
237 /* Comma expected */
238 ConsumeComma ();
239
240 /* Type */
241 if (CurTok.Tok != TOK_STRCON) {
242 ErrorSkip ("String constant expected");
243 return;
244 }
245 Type = ValidateType (&CurTok.SVal);
246 if (Type < 0) {
247 return;
248 }
249 NextTok ();
250
251 /* Comma expected */
252 ConsumeComma ();
253
254 /* The storage class follows */
255 if (CurTok.Tok != TOK_IDENT) {
256 ErrorSkip ("Storage class specifier expected");
257 return;
258 }
259 switch (GetSubKey (StorageKeys, sizeof (StorageKeys)/sizeof (StorageKeys[0]))) {
260 case 0: Flags = HLL_TYPE_FUNC | HLL_SC_EXTERN; break;
261 case 1: Flags = HLL_TYPE_FUNC | HLL_SC_STATIC; break;
262 default: ErrorSkip ("Storage class specifier expected"); return;
263 }
264 NextTok ();
265
266 /* Comma expected */
267 ConsumeComma ();
268
269 /* Assembler name follows */
270 if (CurTok.Tok != TOK_STRCON) {
271 ErrorSkip ("String constant expected");
272 return;
273 }
274 AsmName = GetStrBufId (&CurTok.SVal);
275 NextTok ();
276
277 /* There may only be one function per scope */
278 if (CurrentScope == RootScope) {
279 ErrorSkip ("Functions may not be used in the root scope");
280 return;
281 } else if (CurrentScope->Type != SCOPE_SCOPE || CurrentScope->Label == 0) {
282 ErrorSkip ("Functions can only be tagged to .PROC scopes");
283 return;
284 } else if (CurrentScope->Label->HLLSym != 0) {
285 ErrorSkip ("Only one HLL symbol per asm symbol is allowed");
286 return;
287 } else if (CurrentScope->Label->Name != AsmName) {
288 ErrorSkip ("Scope label and asm name for function must match");
289 return;
290 }
291
292 /* Add the function */
293 S = NewHLLDbgSym (Flags, Name, Type);
294 S->Sym = CurrentScope->Label;
295 CurrentScope->Label->HLLSym = S;
296 CollAppend (&HLLDbgSyms, S);
297}
298
299
300
301void DbgInfoLine (void)
302/* Parse and handle LINE subcommand of the .dbg pseudo instruction */
303{
304 long Line;
305 FilePos Pos = STATIC_FILEPOS_INITIALIZER;
306
307 /* Any new line info terminates the last one */
308 if (CurLineInfo) {
309 EndLine (CurLineInfo);
310 CurLineInfo = 0;
311 }
312
313 /* If a parameters follow, this is actual line info. If no parameters
314 ** follow, the last line info is terminated.
315 */
316 if (CurTok.Tok == TOK_SEP) {
317 return;
318 }
319
320 /* Parameters are separated by a comma */
321 ConsumeComma ();
322
323 /* The name of the file follows */
324 if (CurTok.Tok != TOK_STRCON) {
325 ErrorSkip ("String constant expected");
326 return;
327 }
328
329 /* Get the index in the file table for the name */
330 Pos.Name = GetFileIndex (&CurTok.SVal);
331
332 /* Skip the name */
333 NextTok ();
334
335 /* Comma expected */
336 ConsumeComma ();
337
338 /* Line number */
339 Line = ConstExpression ();
340 if (Line < 0) {
341 ErrorSkip ("Line number is out of valid range");
342 return;
343 }
344 Pos.Line = Line;
345
346 /* Generate a new external line info */
347 CurLineInfo = StartLine (&Pos, LI_TYPE_EXT, 0);
348}
349
350
351
352void DbgInfoSym (void)
353/* Parse and handle SYM subcommand of the .dbg pseudo instruction */
354{
355 static const char* const StorageKeys[] = {
356 "AUTO",
357 "EXTERN",
358 "REGISTER",
359 "STATIC",
360 };
361
362 unsigned Name;
363 int Type;
364 unsigned AsmName = EMPTY_STRING_ID;
365 unsigned Flags;
366 int Offs = 0;
367 HLLDbgSym* S;
368
369
370 /* Parameters are separated by a comma */
371 ConsumeComma ();
372
373 /* Name */
374 if (CurTok.Tok != TOK_STRCON) {
375 ErrorSkip ("String constant expected");
376 return;
377 }
378 Name = GetStrBufId (&CurTok.SVal);
379 NextTok ();
380
381 /* Comma expected */
382 ConsumeComma ();
383
384 /* Type */
385 if (CurTok.Tok != TOK_STRCON) {
386 ErrorSkip ("String constant expected");
387 return;
388 }
389 Type = ValidateType (&CurTok.SVal);
390 if (Type < 0) {
391 return;
392 }
393 NextTok ();
394
395 /* Comma expected */
396 ConsumeComma ();
397
398 /* The storage class follows */
399 if (CurTok.Tok != TOK_IDENT) {
400 ErrorSkip ("Storage class specifier expected");
401 return;
402 }
403 switch (GetSubKey (StorageKeys, sizeof (StorageKeys)/sizeof (StorageKeys[0]))) {
404 case 0: Flags = HLL_SC_AUTO; break;
405 case 1: Flags = HLL_SC_EXTERN; break;
406 case 2: Flags = HLL_SC_REG; break;
407 case 3: Flags = HLL_SC_STATIC; break;
408 default: ErrorSkip ("Storage class specifier expected"); return;
409 }
410
411 /* Skip the storage class token and the following comma */
412 NextTok ();
413 ConsumeComma ();
414
415 /* The next tokens depend on the storage class */
416 if (Flags == HLL_SC_AUTO) {
417 /* Auto: Stack offset follows */
418 Offs = ConstExpression ();
419 } else {
420 /* Register, extern or static: Assembler name follows */
421 if (CurTok.Tok != TOK_STRCON) {
422 ErrorSkip ("String constant expected");
423 return;
424 }
425 AsmName = GetStrBufId (&CurTok.SVal);
426 NextTok ();
427
428 /* For register, an offset follows */
429 if (Flags == HLL_SC_REG) {
430 ConsumeComma ();
431 Offs = ConstExpression ();
432 }
433 }
434
435 /* Add the function */
436 S = NewHLLDbgSym (Flags | HLL_TYPE_SYM, Name, Type);
437 S->AsmName = AsmName;
438 S->Offs = Offs;
439 CollAppend (&HLLDbgSyms, S);
440}
441
442
443
444void DbgInfoCheck (void)
445/* Do checks on all hll debug info symbols when assembly is complete */
446{
447 /* When parsing the debug statements for HLL symbols, we have already
448 ** tagged the functions to their asm counterparts. This wasn't done for
449 ** C symbols, since we will allow forward declarations. So we have to
450 ** resolve the normal C symbols now.
451 */
452 unsigned I;
453 for (I = 0; I < CollCount (&HLLDbgSyms); ++I) {
454
455 /* Get the next symbol */
456 HLLDbgSym* S = CollAtUnchecked (&HLLDbgSyms, I);
457
458 /* Ignore functions and auto symbols, because the later live on the
459 ** stack and don't have corresponding asm symbols.
460 */
461 if (HLL_IS_FUNC (S->Flags) || HLL_GET_SC (S->Flags) == HLL_SC_AUTO) {
462 continue;
463 }
464
465 /* Safety */
466 CHECK (S->Sym == 0 && S->Scope != 0);
467
468 /* Search for the symbol name */
469 S->Sym = SymFindAny (S->Scope, GetStrBuf (S->AsmName));
470 if (S->Sym == 0) {
471 PError (&S->Pos, "Assembler symbol '%s' not found",
472 GetString (S->AsmName));
473 } else {
474 /* Set the backlink */
475 S->Sym->HLLSym = S;
476 }
477
478 }
479}
480
481
482
483void WriteHLLDbgSyms (void)
484/* Write a list of all high level language symbols to the object file. */
485{
486 unsigned I;
487
488 /* Only if debug info is enabled */
489 if (DbgSyms) {
490
491 /* Write the symbol count to the list */
492 ObjWriteVar (CollCount (&HLLDbgSyms));
493
494 /* Walk through list and write all symbols to the file. */
495 for (I = 0; I < CollCount (&HLLDbgSyms); ++I) {
496
497 /* Get the next symbol */
498 HLLDbgSym* S = CollAtUnchecked (&HLLDbgSyms, I);
499
500 /* Get the type of the symbol */
501 unsigned SC = HLL_GET_SC (S->Flags);
502
503 /* Remember if the symbol has debug info attached
504 ** ### This should go into DbgInfoCheck
505 */
506 if (S->Sym && S->Sym->DebugSymId != ~0U) {
507 S->Flags |= HLL_DATA_SYM;
508 }
509
510 /* Write the symbol data */
511 ObjWriteVar (S->Flags);
512 ObjWriteVar (S->Name);
513 if (HLL_HAS_SYM (S->Flags)) {
514 ObjWriteVar (S->Sym->DebugSymId);
515 }
516 if (SC == HLL_SC_AUTO || SC == HLL_SC_REG) {
517 ObjWriteVar (S->Offs);
518 }
519 ObjWriteVar (S->Type);
520 ObjWriteVar (S->Scope->Id);
521 }
522
523 } else {
524
525 /* Write a count of zero */
526 ObjWriteVar (0);
527
528 }
529}
530