Changes to work towards compatability with IBM's version of dyninst.
[dyninst.git] / dyninstAPI / src / CodeView.C
1 /*
2  * Copyright (c) 1996-1999 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 // $Id: CodeView.C,v 1.10 2001/08/29 23:25:27 hollings Exp $
43
44 #include <assert.h>
45
46 #include <iostream.h>
47 #include <iomanip.h>
48
49 #include "common/h/String.h"
50 #include "common/h/Vector.h"
51 #include "dyninstAPI/src/CodeView.h"
52 #include "dyninstAPI/src/NTTypes.h"
53
54
55 //---------------------------------------------------------------------------
56 // CodeView methods
57 //---------------------------------------------------------------------------
58
59 bool
60 CodeView::Parse( void )
61 {
62         DWORD i;
63
64
65         // verify the CodeView signature
66         // currently, we only support the NB11 format
67         if( strncmp( pBase, "NB11", 4 ) != 0 )
68         {
69                 // indicate that we do not understand this CodeView format
70                 return false;
71         }
72
73         // obtain access to the subsection directory
74         SDHeader* pSDHdr = (SDHeader*)(pBase + *(DWORD*)(pBase + 4));
75
76         // parse the subsections, extracting the information we need
77         for( i = 0; i < pSDHdr->cDir; i++ )
78         {
79                 SDEntry* pEntry = 
80                         (SDEntry*)(((char*)pSDHdr) +
81                 pSDHdr->cbDirHeader + i * pSDHdr->cbDirEntry);
82
83                 switch( pEntry->sst )
84                 {
85                 case sstModule:
86                         ParseModuleSubsection( pEntry );
87                         break;
88
89                 case sstLibraries:
90                         ParseLibrariesSubsection( pEntry );
91                         break;
92
93                 case sstAlignSym:
94                         ParseAlignSymSubsection( pEntry );
95                         break;
96
97                 case sstSrcModule:
98                         ParseSrcModuleSubsection( pEntry );
99                         break;
100
101                 case sstGlobalPub:
102                 case sstStaticSym:
103                 case sstGlobalSym:
104                         ParseSymbolsWithHeaderSubsection( pEntry );
105                         break;
106
107                 default:
108                         // it is a subsection type we do not care about - skip it
109                         break;
110                 }
111         }
112
113         return true;
114 }
115
116
117
118 void
119 CodeView::ParseModuleSubsection( SDEntry* pEntry )
120 {
121         // ensure that the modules vector contains an element for this module
122         // recall that the modules vector uses a one-based index
123         if( pEntry->iMod >= modules.size() )
124         {
125                 modules.resize( pEntry->iMod + 1 );
126         }
127
128         // make a new entry for this module, starting with this module subsection
129         modules[pEntry->iMod] =
130         Module((ModuleSubsection*)(pBase + pEntry->offset), textId );
131 }
132
133
134 void
135 CodeView::ParseLibrariesSubsection( SDEntry* pEntry )
136 {
137         const char* curr = pBase + pEntry->offset;
138
139         while( curr < (pBase + pEntry->offset + pEntry->cb) )
140         {
141                 // add an entry for this library
142                 libs.push_back(curr);
143
144                 // advance to the next string
145                 curr += (*curr + 1);
146         }
147 }
148
149
150 void
151 CodeView::ParseSymbolsWithHeaderSubsection( SDEntry* pEntry )
152 {
153         SymHeader* pSymHdr = (SymHeader*)(pBase + pEntry->offset);
154
155         syms.Parse( ((char*)pSymHdr) + sizeof(SymHeader), pSymHdr->cbSymbol );
156 }
157
158
159 void
160 CodeView::ParseAlignSymSubsection( SDEntry* pEntry )
161 {
162         // associate this subsection with the correct module
163         Module& mod = modules[pEntry->iMod];
164         mod.pas = (AlignSymSubsection*)(pBase + pEntry->offset);
165
166         // parse the symbols represented in this section
167         mod.syms.Parse( (const char*)mod.pas, pEntry->cb );
168 }
169
170
171 void
172 CodeView::ParseSrcModuleSubsection( SDEntry* pEntry )
173 {
174         // associate this subsection with the correct module
175         Module& mod = modules[pEntry->iMod];
176         mod.psrc = (SrcModuleSubsection*)(pBase + pEntry->offset);
177 }
178
179 #ifdef BPATCH_LIBRARY
180
181 #include "LineInformation.h"
182
183 /**
184  * @param srcModuleTable the pointer to the beginning of the srcModuleSection 
185  *                       of the debug information. This is the address where 
186  *                       the line information table can be found in the exec.
187  * @param baseAddr       the information for line numbers is given relative to
188  *                       beginning of the module. That is for a line number the
189  *                       information that can be obtained is the relative addres
190  *                       with respect to module so we pass also the start addres
191  *                       of the code in the module.
192  * @param lineInformation lineInformation object of ours
193  * 
194  * !!!!!! IMPORTANT !!!!!!!
195  * This function only generates the data structures for source files and
196  * the mappings lineNumber <-> lineAddress in the source files. It does not
197  * relate the functions to the lines or files yet. Actual functions are related
198  * to data structure in CreateTypeAndLineInfo function.
199  */
200
201 void
202 CodeView::CreateLineInfo( const char* srcModuleTable, DWORD baseAddr ,
203                           LineInformation* lineInformation)
204 {
205         SrcModuleSubsection* psrc = (SrcModuleSubsection*)srcModuleTable;
206
207         //get the number of segments in file to skip some fields
208         WORD segInModule = psrc->cSeg;
209         WORD fileInModule = psrc->cFile;
210
211         //cerr << "NUMBER OF FILES " << fileInModule << "\n";
212
213         //process each file in the module
214         for(WORD fileE=0 ; fileE < fileInModule ; fileE++){
215
216                 //get the offset and claculate the address for the file record
217                 DWORD fileEOffset = 
218                         *(DWORD*)(srcModuleTable + (1 + fileE)*sizeof(DWORD));
219                 const char* fileEAddress = srcModuleTable + fileEOffset;
220                 SrcModuleSubsection::FileInfo* fileI = 
221                         (SrcModuleSubsection::FileInfo*)fileEAddress;
222
223                 //get the number of segments in  this file record
224                 WORD segInFile = fileI->cSegFile;
225
226                 //get the pointer for the file name and then create string
227                 const char* ptr = 
228                         fileEAddress + sizeof(DWORD)+ 3*segInFile*sizeof(DWORD);
229                 LPString currentSourceFile(ptr);
230
231                 //cerr << "FILE NAME : " <<  (string)currentSourceFile << "\n";
232                 lineInformation->insertSourceFileName(string("___tmp___"),
233                                                       (string)currentSourceFile);
234
235                 for(WORD segmentE = 0; segmentE < segInFile; segmentE++){
236                         //calculate the segment table offset and the address
237                         //for the table
238                         DWORD segmentEOffset = 
239                                 *(DWORD*)(fileEAddress+ (1+segmentE)*sizeof(DWORD));
240                         const char* segmentEAddress = 
241                                 srcModuleTable + segmentEOffset;
242
243                         //find how many pais exist in the table for line numbers
244                         WORD pairInSegment = 
245                                 *(WORD*)(segmentEAddress + sizeof(WORD));
246
247                         //calculate the starting addresses for parallel arrays
248                         const char* lineOffsetAddress = 
249                                         segmentEAddress + sizeof(DWORD); 
250                         const char* lineNumberAddress = 
251                                 lineOffsetAddress + sizeof(DWORD)*pairInSegment;
252
253                         //for each pair (number,address) mapping insert to
254                         //line number data structure
255                         for(WORD pairE = 0; pairE < pairInSegment; pairE++){
256                                 DWORD lineOffset = *(DWORD*)(lineOffsetAddress + pairE*sizeof(DWORD));
257                                 WORD lineNumber = *(WORD*)(lineNumberAddress + pairE*sizeof(WORD));
258                                 //cerr << "LINE : " << lineNumber << " -- "
259                                 //     << hex << (lineOffset + baseAddr) 
260                                 //     <<  " : " << lineOffset << dec << "\n";
261                                 lineInformation->insertLineAddress(
262                                         string("___tmp___"),
263                                         (string)currentSourceFile,
264                                         lineNumber,lineOffset + baseAddr);
265                         }
266                 }
267         }
268         //since at this point no function info is available we used
269         //a temporary function to insert the data but later this
270         //function is not going to be used so we delete the entry for
271         //this function.
272
273         if(fileInModule)
274                 lineInformation->deleteFunction(string("___tmp___"));
275 }
276
277 //
278 // Create type information for a specific module
279 //
280 void
281 CodeView::CreateTypeAndLineInfo( BPatch_module *inpMod , DWORD baseAddr ,
282                                  LineInformation* lineInformation)
283 {
284         DWORD i;
285
286         // verify the CodeView signature
287         // currently, we only support the NB11 format
288         if( strncmp( pBase, "NB11", 4 ) != 0 )
289         {
290                 // indicate that we do not understand this CodeView format
291                 return;
292         }
293
294         // obtain access to the subsection directory
295         SDHeader* pSDHdr = (SDHeader*)(pBase + *(DWORD*)(pBase + 4));
296
297         //Find inp module name
298         char inpModName[1024];
299         inpMod->getName(inpModName, 1024);
300         char *ptr = strrchr(inpModName, '.');
301         if (ptr)
302                 *ptr = '\0';
303
304         Module *mod = NULL;
305         SDEntry *alignSubSec = NULL;
306         int iMod = -1;
307         TypesSubSection *pTypeBase = NULL;
308         SrcModuleSubsection* lineData = NULL; //to check line info is available
309
310         // parse the subsections, extracting the information we need
311         for( i = 0; i < pSDHdr->cDir; i++ )
312         {
313                 SDEntry* pEntry =
314                         (SDEntry*)(((char*)pSDHdr) +
315                 pSDHdr->cbDirHeader + i * pSDHdr->cbDirEntry);
316
317                 switch( pEntry->sst )
318                 {
319                 case sstModule: 
320                 {
321                         ModuleSubsection *pmod = (ModuleSubsection *) 
322                                                         (pBase + pEntry->offset);
323
324                         LPString lpsName ( ((char*)pmod) + sizeof(ModuleSubsection) +
325                                         pmod->cSeg * sizeof( ModuleSubsection::SegInfo ) );
326
327                         char modName[1024];
328                         strcpy(modName, ((string)lpsName).string_of());
329                         ptr = strrchr(modName, '.');
330                         if (ptr)
331                                 *ptr = '\0';
332
333                         if ( strcmp(modName, inpModName) == 0 ) {
334                                 // We found correct module
335                                 mod = new Module(pmod, textId);
336                                 iMod = pEntry->iMod;
337                         }
338
339                         break;
340                 }
341
342                 case sstAlignSym:
343                         // check whether this subsection is in the correct module
344                         if (mod && (iMod == pEntry->iMod) ) {
345                                 mod->pas = (AlignSymSubsection*)(pBase + pEntry->offset);
346                                 alignSubSec = pEntry;
347                         }
348                         break;
349
350                 case sstGlobalTypes:
351                         pTypeBase = (TypesSubSection *) (pBase + pEntry->offset);
352                         break;
353
354                 case sstSrcModule:
355                         if(mod && (iMod == pEntry->iMod)){ 
356                                 lineData = (SrcModuleSubsection*)(pBase + pEntry->offset);
357                                 mod->psrc = lineData ;
358                         }
359                         break;
360                 default:
361                         // it is a subsection type we do not care about - skip it
362                         break;
363                 }
364         }
365
366         if (!mod)
367                 return; //We could not find the input module
368
369         //if the debug section do not contain the line info section for 
370         //the module we return witha warning.
371         if(lineData)
372                 CreateLineInfo((const char*)(mod->psrc),baseAddr,
373                                lineInformation);
374         else
375                 cerr << "WARNING : CodeView::CreateTypeAndLineInfo"
376                      << " can not create Line Information for : "
377                      << inpModName << ".\n";
378
379         mod->syms.CreateTypeInfo( (const char *)mod->pas, alignSubSec->cb,
380                                         pTypeBase, inpMod,lineInformation);
381 }
382 #endif // BPATCH_LIBRARY
383
384 //---------------------------------------------------------------------------
385 // CodeView::Symbols methods
386 //---------------------------------------------------------------------------
387
388
389 void
390 CodeView::Symbols::Parse( const char* pSymBase, DWORD cb )
391 {
392         // scan the symbols linearly
393         SymRecord* curr = (SymRecord*)pSymBase;
394         while( ((char*)curr) < (pSymBase + cb) )
395         {
396                 // handle the symbol record
397                 switch( curr->index )
398                 {
399                 case S_LPROC32:
400                         // add the entry to our list of functions
401                         lprocs.push_back(( (SymRecordProc*)curr ));
402                         break;
403
404                 case S_GPROC32:
405                         // add the entry to our list of functions
406                         gprocs.push_back(( (SymRecordProc*)curr ));
407                         break;
408
409                 case S_LDATA32:
410                         // add the entry to our list of variables
411                         lvars.push_back(( (SymRecordData*)curr ));
412                         break;
413
414                 case S_GDATA32:
415                         // add the entry to our list of variables
416                         gvars.push_back(( (SymRecordData*)curr ));
417                         break;
418
419                 case S_LABEL32:
420                         labels.push_back(( (SymRecordLabel*)curr ));
421                         break;
422
423                 case S_BPREL32:
424                         bprels.push_back(( (SymRecordBPRel*)curr ));
425                         break;
426
427                 case S_THUNK32:
428                         thunks.push_back(( (SymRecordThunk*)curr ));
429                         break;
430
431                 case S_END:
432                         // nothing to do for end markers
433                         break;
434
435                 case S_ALIGN:
436                         // skip padding records
437                         break;
438
439         case S_PUB32:
440             pubs.push_back((SymRecordData*)curr);
441             break;
442
443                 default:
444                         // it is a record type that we do not care about
445                         break;
446                 }
447
448                 // advance to the next symbol
449                 curr = (SymRecord*)(((char*)curr) + curr->length + sizeof(WORD));
450         }
451 }
452
453
454
455 CodeView::Symbols&
456 CodeView::Symbols::operator=( const CodeView::Symbols& syms )
457 {
458         if( &syms != this )
459         {
460                 gprocs = syms.gprocs;           // global functions
461                 lprocs = syms.lprocs;           // local functions
462                 gvars = syms.gvars;                     // global variables
463                 lvars = syms.lvars;                     // local variables
464                 bprels = syms.bprels;           // stack variables
465                 labels = syms.labels;           // labels
466                 thunks = syms.thunks;           // thunks (code outside of functions)
467         pubs = syms.pubs;           // public (catch-all) symbols
468         }
469         return *this;
470 }
471
472 #ifdef BPATCH_LIBRARY
473 //
474 // Creates type information for the symbols in the specified module
475 //
476 void
477 CodeView::Symbols::CreateTypeInfo( const char* pSymBase, DWORD cb, 
478                                 TypesSubSection *pTypeBase, BPatch_module *mod ,
479                                 LineInformation* lineInformation)
480 {
481         char currFuncName[1024];
482         char symName[1024];
483         int len;
484         int fparam = 0;
485
486         BPatch_function  *fp = NULL;
487         BPatch_type *ptrType = NULL;
488         BPatch_localVar *locVar = NULL;
489
490         //Initialize required member variables
491         char *startAddr = ((char *)pTypeBase->offType) + pTypeBase->cType * sizeof(DWORD);
492
493         // scan the symbols linearly
494         SymRecord* curr = (SymRecord*)pSymBase;
495         while( ((char*)curr) < (pSymBase + cb) )
496         {
497                 // handle the symbol record
498                 switch( curr->index )
499                 {
500                 case S_LPROC32:
501                 case S_GPROC32:
502                         len = (int) ( (SymRecordProc*)curr )->name[0];
503                         strncpy(currFuncName, &( (SymRecordProc*)curr )->name[1], len);
504                         currFuncName[len] = '\0';
505
506                         //Find function in the module
507                         fp = mod->findFunction(currFuncName);
508                         if (fp) {
509                                 lineInformation->insertFunction(
510                                         string(currFuncName),
511                                         (Address)(fp->getBaseAddr()),
512                                         fp->getSize());
513                                 DWORD offset = pTypeBase->offType[((SymRecordProc*)curr )->procType - 0x1000];
514                                 TypeRec *trec = (TypeRec *)(startAddr + offset);
515                                 if (trec->leaf == LF_PROCEDURE)
516                                         fparam = ((ProcTypeRec *)trec)->parms;
517                                 else if (trec->leaf == LF_MFUNCTION) {
518                                         BPatch_type *thisType = ExploreType(mod,
519                                                 ((MFuncTypeRec *)trec)->thisType,
520                                                 pTypeBase, startAddr);
521                                         if (thisType && 
522                                                 !strcmp(thisType->getName(), "void"))
523                                                 fparam = ((MFuncTypeRec *)trec)->parms;
524                                         else
525                                                 fparam = ((MFuncTypeRec *)trec)->parms + 1;
526                                 }
527
528                                 ptrType = ExploreType(mod, ((ProcTypeRec *)trec)->rvtype, 
529                                                                 pTypeBase, startAddr);
530                                 if (ptrType)
531                                         fp->setReturnType(ptrType);
532                         }
533                         break;
534
535                 case S_LDATA32:
536                 case S_GDATA32:
537                 case S_PUB32:
538                         // add the entry to our list of variables
539                         len = (int) ( (SymRecordData*)curr )->name[0];
540                         strncpy(symName, &( (SymRecordData*)curr )->name[1], len);
541                         symName[len] = '\0';
542                         ptrType = ExploreType(mod, ( (SymRecordData*)curr )->type,
543                                                                 pTypeBase, startAddr);
544                         if (ptrType)
545                                 mod->moduleTypes->addGlobalVariable(symName, ptrType);
546                         break;
547
548                 case S_BPREL32:
549                         len = (int) ( (SymRecordBPRel*)curr )->name[0];
550                         strncpy(symName, &( (SymRecordBPRel*)curr )->name[1], len);
551                         symName[len] = '\0';
552                         if (fp && ( (SymRecordBPRel*)curr )->offset) {
553                                 ptrType = ExploreType(mod, ( (SymRecordBPRel*)curr )->type,
554                                                                 pTypeBase, startAddr);
555                                 if (ptrType) {
556                                         locVar = new BPatch_localVar(symName, ptrType, -1, 
557                                                         ((SymRecordBPRel*)curr )->offset);
558                                         if (fparam) {
559                                                 fp->funcParameters->addLocalVar(locVar);
560                                                 fp->addParam(symName, ptrType, -1, 
561                                                         ((SymRecordBPRel*)curr )->offset);
562                                                 fparam--;
563                                         }
564                                         else {
565                                                 fp->localVariables->addLocalVar(locVar);
566                                         }
567                                 }
568                         }
569                         break;
570
571                 case S_CONSTANT:
572                 {
573                         // Constant vars
574
575                         char *name;
576                         if ( ((SymRecordCons *)curr)->value < LF_NUMERIC )
577                                 name = ((SymRecordCons *)curr)->name;
578                         else
579                                 name = (char *)&((SymRecordCons *)curr)->value +
580                                                                 sizeof(DWORD);
581
582                         len = (int)name[0];
583                         strncpy(symName, &name[1], len);
584                         symName[len] = '\0';
585
586                         ptrType = ExploreType(mod, ( (SymRecordCons *)curr )->type,
587                                                                 pTypeBase, startAddr);
588                         if (ptrType)
589                                 mod->moduleTypes->addGlobalVariable(symName, ptrType);
590                         break;
591                 }
592
593                 case S_UDT:
594                         // Typedefs
595                         break;
596
597                 default:
598                         // it is a record type that we do not care about
599                         break;
600                 }
601
602                 // advance to the next symbol
603                 curr = (SymRecord*)(((char*)curr) + curr->length + sizeof(WORD));
604         }
605 }
606
607 //
608 // Mapping from CodeView types to DyninstAPI types
609 //
610
611 BPatch_type *
612 CodeView::Symbols::CreatePrimitiveType(DWORD index)
613 {
614         BPatch_type *lastType;
615
616         switch(index) {
617         case T_NOTYPE: //Regarded as void
618         case T_VOID:
619                 lastType = new BPatch_type("void", -11, BPatch_built_inType, 0);
620                 break;
621         case T_PVOID:
622         case T_PFVOID:
623         case T_PHVOID:
624         case T_32PVOID:
625         case T_32PFVOID:
626         case T_64PVOID:
627                 lastType = new BPatch_type("void", -11, BPatch_built_inType, 0);
628                 lastType = new BPatch_type("", -1, BPatch_pointer, lastType);
629                 break;
630         case T_CHAR:
631         case T_RCHAR:
632                 lastType = new BPatch_type("char", -2, BPatch_built_inType, 1);
633                 break;
634         case T_PCHAR:
635         case T_PFCHAR:
636         case T_PHCHAR:
637         case T_32PCHAR:
638         case T_32PFCHAR:
639         case T_64PCHAR:
640         case T_PRCHAR:
641         case T_PFRCHAR:
642         case T_PHRCHAR:
643         case T_32PRCHAR:
644         case T_32PFRCHAR:
645         case T_64PRCHAR:
646                 lastType = new BPatch_type("char", -2, BPatch_built_inType, 1);
647                 lastType = new BPatch_type("", -1, BPatch_pointer, lastType);
648                 break;
649         case T_UCHAR:
650                 lastType = new BPatch_type("unsigned char", -5, BPatch_built_inType, 1);
651                 break;
652         case T_PUCHAR:
653         case T_PFUCHAR:
654         case T_PHUCHAR:
655         case T_32PUCHAR:
656         case T_32PFUCHAR:
657         case T_64PUCHAR:
658                 lastType = new BPatch_type("unsigned char", -5, BPatch_built_inType, 1);
659                 lastType = new BPatch_type("", -1, BPatch_pointer, lastType);
660                 break;
661         case T_SHORT:
662         case T_INT2:
663                 lastType = new BPatch_type("short", -3, BPatch_built_inType, 2);
664                 break;
665         case T_PINT2:
666         case T_PFINT2:
667         case T_PHINT2:
668         case T_32PINT2:
669         case T_32PFINT2:
670         case T_64PINT2:
671         case T_PSHORT:
672         case T_PFSHORT:
673         case T_PHSHORT:
674         case T_32PSHORT:
675         case T_32PFSHORT:
676         case T_64PSHORT:
677                 lastType = new BPatch_type("short", -3, BPatch_built_inType, 2);
678                 lastType = new BPatch_type("", -1, BPatch_pointer, lastType);
679                 break;
680         case T_USHORT:
681         case T_UINT2:
682                 lastType = new BPatch_type("unsigned short", -7, BPatch_built_inType, 2);
683                 break;
684         case T_PUINT2:
685         case T_PFUINT2:
686         case T_PHUINT2:
687         case T_32PUINT2:
688         case T_32PFUINT2:
689         case T_64PUINT2:
690         case T_PUSHORT:
691         case T_PFUSHORT:
692         case T_PHUSHORT:
693         case T_32PUSHORT:
694         case T_32PFUSHORT:
695         case T_64PUSHORT:
696                 lastType = new BPatch_type("unsigned short", -7, BPatch_built_inType, 2);
697                 lastType = new BPatch_type("", -1, BPatch_pointer, lastType);
698                 break;
699         case T_INT4:
700                 lastType = new BPatch_type("int", -1, BPatch_built_inType, 4);
701                 break;
702         case T_PINT4:
703         case T_PFINT4:
704         case T_PHINT4:
705         case T_32PINT4:
706         case T_32PFINT4:
707         case T_64PINT4:
708                 lastType = new BPatch_type("int", -1, BPatch_built_inType, 4);
709                 lastType = new BPatch_type("", -1, BPatch_pointer, lastType);
710                 break;
711         case T_UINT4:
712                 lastType = new BPatch_type("unsigned int", -8, BPatch_built_inType, 4);
713                 break;
714         case T_PUINT4:
715         case T_PFUINT4:
716         case T_PHUINT4:
717         case T_32PUINT4:
718         case T_32PFUINT4:
719         case T_64PUINT4:
720                 lastType = new BPatch_type("unsigned int", -8, BPatch_built_inType, 4);
721                 lastType = new BPatch_type("", -1, BPatch_pointer, lastType);
722                 break;
723         case T_LONG:
724                 lastType = new BPatch_type("long", -4, BPatch_built_inType, sizeof(long));
725                 break;
726         case T_PLONG:
727         case T_PFLONG:
728         case T_PHLONG:
729         case T_32PLONG:
730         case T_32PFLONG:
731         case T_64PLONG:
732                 lastType = new BPatch_type("long", -4, BPatch_built_inType, sizeof(long));
733                 lastType = new BPatch_type("", -1, BPatch_pointer, lastType);
734                 break;
735         case T_ULONG:
736                 lastType = new BPatch_type("unsigned long", -10, BPatch_built_inType, 
737                                                                 sizeof(unsigned long));
738                 break;
739         case T_PULONG:
740         case T_PFULONG:
741         case T_PHULONG:
742         case T_32PULONG:
743         case T_32PFULONG:
744         case T_64PULONG:
745                 lastType = new BPatch_type("unsigned long", -10, BPatch_built_inType, 
746                                                                 sizeof(unsigned long));
747                 lastType = new BPatch_type("", -1, BPatch_pointer, lastType);
748                 break;
749         case T_REAL32:
750                 lastType = new BPatch_type("float", -12, BPatch_built_inType, 
751                                                                         sizeof(float));
752                 break;
753         case T_PREAL32:
754         case T_PFREAL32:
755         case T_PHREAL32:
756         case T_32PREAL32:
757         case T_32PFREAL32:
758         case T_64PREAL32:
759                 lastType = new BPatch_type("float", -12, BPatch_built_inType,
760                                                                         sizeof(float));
761                 lastType = new BPatch_type("", -1, BPatch_pointer, lastType);
762                 break;
763         case T_REAL64:
764                 lastType = new BPatch_type("double", -13, BPatch_built_inType, 
765                                                                         sizeof(double));
766                 break;
767         case T_PREAL64:
768         case T_PFREAL64:
769         case T_PHREAL64:
770         case T_32PREAL64:
771         case T_32PFREAL64:
772         case T_64PREAL64:
773                 lastType = new BPatch_type("double", -13, BPatch_built_inType, 
774                                                                         sizeof(double));
775                 lastType = new BPatch_type("", -1, BPatch_pointer, lastType);
776                 break;
777         case T_INT8:
778         case T_UINT8:
779                 lastType = new BPatch_type("long long", -32, BPatch_built_inType, 8);
780                 break;
781         case T_PINT8:
782         case T_PUINT8:
783         case T_PFINT8:
784         case T_PFUINT8:
785         case T_PHINT8:
786         case T_PHUINT8:
787         case T_32PINT8:
788         case T_32PUINT8:
789         case T_32PFINT8:
790         case T_32PFUINT8:
791         case T_64PINT8:
792         case T_64PUINT8:
793                 lastType = new BPatch_type("long long", -32, BPatch_built_inType, 8);
794                 lastType = new BPatch_type("", -1, BPatch_pointer, lastType);
795                 break;
796         case T_REAL80:
797                 lastType = new BPatch_type("long double", -14, BPatch_built_inType, 
798                                                                 sizeof(long double));
799                 break;
800         case T_PREAL80:
801         case T_PFREAL80:
802         case T_PHREAL80:
803         case T_32PREAL80:
804         case T_32PFREAL80:
805         case T_64PREAL80:
806                 lastType = new BPatch_type("long double", -14, BPatch_built_inType,
807                                                                 sizeof(long double));
808                 lastType = new BPatch_type("", -1, BPatch_pointer, lastType);
809                 break;
810         default:
811                 lastType = NULL;
812         }
813
814         return lastType;
815 }
816
817 BPatch_visibility AccessType(WORD attribute) {
818         switch(attribute & 0x3) {
819         case 1:
820                 return BPatch_private;
821         case 2:
822                 return BPatch_protected;
823         case 3:
824                 return BPatch_public;
825         }
826
827         return BPatch_visUnknown;
828 }
829
830 void
831 CodeView::Symbols::FindFields(BPatch_module *mod, BPatch_type *mainType, int count,
832                                 DWORD index, TypesSubSection *pTypeBase, char *startAddr)
833 {
834         BPatch_type *memberType = NULL;
835         char fname[1024], *name;
836         int foffset;
837         int fvalue;
838
839         //Find field list
840         DWORD offset = pTypeBase->offType[index - 0x1000];
841         TypeRec *trec = (TypeRec *)(startAddr + offset);
842
843         if (trec->leaf != LF_FIELDLIST) {
844                 printf("Invalid field list entry!\n");
845                 return;
846         }
847
848         // printf("Number of fields: %d\n", count);
849
850         unsigned char *ptr = ((unsigned char *)trec) + sizeof(TypeRec);
851         for(int i=0; i<count; ++i) {
852                 switch( *((WORD *)ptr) ) {
853                 case LF_MEMBER:
854                         if ( ((LFMember *)ptr)->offset < LF_NUMERIC ) {
855                                 foffset = ((LFMember *)ptr)->offset;
856                                 name = ((LFMember *)ptr)->name;
857                         }
858                         else {
859                                 // Need to find offset
860                                 foffset = -1;
861                                 name = ( (char *) &((LFMember *)ptr)->offset) +
862                                                                         sizeof(DWORD);
863                         }
864                                         
865                         strncpy(fname, &name[1], (int)name[0]);
866                         fname[(int)name[0]] = '\0';
867                         memberType = ExploreType(mod, ((LFMember *)ptr)->type, 
868                                                                 pTypeBase, startAddr);
869                         if (memberType == NULL)
870                                 memberType = mod->moduleTypes->findType("void");
871
872                         mainType->addField(fname, BPatch_scalar, memberType, foffset*8, 
873                                                 memberType->getSize(), 
874                                                 AccessType(((LFMember *)ptr)->attribute) );
875
876                         // printf("Field %d is LF_MEMBER %s\n", i, fname);
877
878                         // Move to the next record
879                         ptr = ((unsigned char *)name) + (int)name[0] + 1;
880                         break;
881
882                 case LF_ENUMERATE:
883                         if ( ((LFEnumerate *)ptr)->value < LF_NUMERIC ) {
884                                 fvalue = ((LFEnumerate *)ptr)->value;
885                                 name = ((LFEnumerate *)ptr)->name;
886                         }
887                         else {
888                                 // Need to find value
889                                 fvalue = -1;
890                                 name = ( (char *) &((LFEnumerate *)ptr)->value) +
891                                                                         sizeof(DWORD);
892                         }
893
894                         strncpy(fname, &name[1], (int)name[0]);
895                         fname[(int)name[0]] = '\0';
896                         mainType->addField(name, BPatch_scalar, fvalue);
897
898                         // printf("Field %d is LF_ENUMERATE %s\n", i, fname);
899
900                         ptr = ((unsigned char *)name) + (int)name[0] + 1;
901                         break;
902
903                 case LF_BCLASS:
904                 {
905                         //Find base class type identifier
906                         int baseID = ((LFBclass *)ptr)->type;
907
908                         //Find offset of the base class
909                         if ( ((LFBclass *)ptr)->offset < LF_NUMERIC ) {
910                                 foffset = ((LFBclass *)ptr)->offset;
911                                 ptr += sizeof(LFBclass);
912                         }
913                         else {
914                                 //Need to calculate offset
915                                 foffset = 0;
916                                 ptr = (unsigned char *)&((LFBclass *)ptr)->offset +
917                                                                 sizeof(DWORD);
918                         }
919                                 
920                         //Find base class
921                         BPatch_type *baseCl = mod->moduleTypes->findType(baseID);
922                         if (baseCl && (baseCl->getDataClass() == BPatch_structure) ) {
923
924                                 //Get field descriptions of the base type
925                                 BPatch_Vector<BPatch_field *> *baseClFields = 
926                                                                 baseCl->getComponents();
927                                 for(int fieldNum=0; fieldNum < baseClFields->size(); 
928                                                                         fieldNum++) 
929                                 {
930                                         BPatch_field *field = (*baseClFields)[fieldNum];
931
932                                         if (field->getVisibility() == BPatch_private)
933                                                 continue; //Can not add this member
934
935                                         mainType->addField(field->getName(),
936                                                 field->getTypeDesc(),
937                                                 field->getType(),
938                                                 foffset*8 + field->getOffset(),
939                                                 field->getVisibility());
940                                 }
941                         }
942
943                         // printf("Field %d is LF_BCLASS\n", i);
944
945                         break;
946                 }
947
948                 case LF_ONEMETHOD:
949                         // printf("LF_ONEMETHOD attribute %d\n", ((LFOnemethod *)ptr)->attribute );
950                         if ( ((LFOnemethod *)ptr)->attribute & 0x10 ) {
951                                 //This is an introducing virtual method.
952                                 name = ((LFOnemethod *)ptr)->name + sizeof(DWORD);
953                         }
954                         else
955                                 name = ((LFOnemethod *)ptr)->name;
956
957                         strncpy(fname, &name[1], (int)name[0]);
958                         fname[(int)name[0]] = '\0';
959                         memberType = ExploreType(mod, ((LFOnemethod *)ptr)->type,
960                                                                 pTypeBase, startAddr);
961
962                         if (memberType == NULL)
963                                 memberType = mod->moduleTypes->findType("void");
964
965                         mainType->addField(fname, BPatch_dataMethod, memberType, 0, 0);
966
967                         // printf("Field %d is LF_ONEMETHOD %s\n", i, fname);
968
969                         ptr = (unsigned char *)name + (int)name[0] + 1;
970                         break;
971
972                 case LF_METHOD:
973                         strncpy(fname, &((LFMethod *)ptr)->name[1],
974                                                 (int)((LFMethod *)ptr)->name[0]);
975                         fname[(int)((LFMethod *)ptr)->name[0]] = '\0';
976                         memberType = mod->moduleTypes->findType("void");
977                         mainType->addField(fname, BPatch_dataMethod, memberType, 0, 0);
978                         ptr = (unsigned char *)((LFMethod *)ptr)->name + 
979                                                 (int)((LFMethod *)ptr)->name[0] + 1;
980
981                         // printf("Field %d is LF_METHOD %s\n", i, fname);
982
983                         break;
984
985                 case LF_STMEMBER:
986                         //Do not know what to do! Just skip this
987                         strncpy(fname, &((LFStmember *)ptr)->name[1],
988                                                 (int)((LFStmember *)ptr)->name[0]);
989                         fname[(int)((LFStmember *)ptr)->name[0]] = '\0';
990
991                         // printf("Field %d is LF_STMEMBER %s\n", i, fname);
992
993                         ptr = (unsigned char *)((LFStmember *)ptr)->name +
994                                         (int)((LFStmember *)ptr)->name[0] + 1;
995                         break;
996                 case LF_VBCLASS:
997                 case LF_IVBCLASS:
998                         // Do not know what to do! Just skip it
999                         if ( ((LFVbclass *)ptr)->vbpoff < LF_NUMERIC ) 
1000                                 ptr = (unsigned char *)&((LFVbclass *)ptr)->vbpoff +
1001                                         sizeof(WORD);
1002                         else
1003                                 ptr = (unsigned char *)&((LFVbclass *)ptr)->vbpoff +
1004                                         sizeof(DWORD);
1005
1006                         if ( *((WORD *)ptr) < LF_NUMERIC ) 
1007                                 ptr += sizeof(WORD);
1008                         else
1009                                 ptr += sizeof(DWORD);
1010                         
1011                         // printf("Field %d is LF_LF_VBCLASS or LF_IVBCLASS\n", i);
1012                         break;
1013
1014                 case LF_VFUNCTAB:
1015                         // Do not know what to do! Just skip it.
1016                         // printf("Field %d is LF_VFUNCTAB\n", i);
1017
1018                         ptr += sizeof(LFVfunctab);
1019
1020                         break;
1021
1022                 case LF_FRIENDFCN:
1023                         printf("LF_FRIENDFCN is not handled!\n");
1024                         break;
1025                 case LF_INDEX:
1026                         printf("LF_INDEX is not handled!\n");
1027                         break;
1028                 case LF_NESTTYPE:
1029                         printf("LF_NESTTYPE is not handled!\n");
1030                         break;
1031                 case LF_FRIENDCLS:
1032                         printf("LF_FRIENDCLS is not handled!\n");
1033                         break;
1034                 case LF_VFUNCOFF:
1035                         printf("LF_VFUNCOFF is not handled!\n");
1036                         break;
1037                 case LF_NESTTYPEEX:
1038                         printf("LF_NESTTYPEEX is not handled!\n");
1039                         break;
1040                 case LF_MEMBERMODIFY:
1041                         printf("LF_MEMBERMODIFY is not handled!\n");
1042                         break;
1043                 default:
1044                         // printf("Unknown leaf index in field %d %x\n", i, *((WORD *)ptr));
1045                         return;
1046                 }
1047
1048                 //Check for padding bytes
1049                 while (*ptr > LF_PAD0) 
1050                         ptr += (*ptr - LF_PAD0);
1051         }
1052 }
1053
1054 BPatch_type *
1055 CodeView::Symbols::ExploreType(BPatch_module *mod, DWORD index, 
1056                                TypesSubSection *pTypeBase, char *startAddr)
1057 {
1058         BPatch_type *lastType, *newType = NULL;
1059         char typeName[1024];
1060
1061         //First check whether or not this type was created before
1062         newType = mod->moduleTypes->findType(index);
1063         if (newType)
1064                 return newType;
1065
1066         if (index < 0x1000) {
1067                 // This is a primitive type
1068                 newType = CreatePrimitiveType(index);
1069                 //Add type definition
1070                 if (newType) {
1071                         newType->setID(index);
1072                         mod->moduleTypes->addType(newType);
1073                 }
1074                 return newType;
1075         }
1076
1077
1078         //Handle non-primitive type
1079         DWORD offset = pTypeBase->offType[index - 0x1000];
1080         TypeRec *trec = (TypeRec *)(startAddr + offset);
1081
1082         switch(trec->leaf) {
1083         case LF_MODIFIER:
1084                 newType = ExploreType(mod, ((LFModifier *)trec)->index, 
1085                                                         pTypeBase, startAddr);
1086                 break;
1087         case LF_POINTER:
1088                 lastType = ExploreType(mod, ((LFPointer *)trec)->type,
1089                                                         pTypeBase, startAddr);
1090                 if (lastType)
1091                         newType = new BPatch_type("", -1, BPatch_pointer, lastType);
1092                 break;
1093         case LF_ARRAY:
1094                 lastType = ExploreType(mod, ((LFArray *)trec)->elemtype,
1095                                                         pTypeBase, startAddr);
1096                 if (lastType) {
1097                         int arrLen;
1098                         char *arrName;
1099
1100                         if ( ((LFArray *)trec)->length < LF_NUMERIC ) {
1101                                 arrLen = ((LFArray *)trec)->length;
1102                                 arrName = (char *) ((LFArray *)trec)->name;
1103                         }
1104                         else {
1105                                 //Need to calculate arrLen
1106                                 arrLen = 0;
1107                                 arrName = ( (char *) &((LFArray *)trec)->length ) + 
1108                                                                         sizeof(DWORD);
1109                         }
1110                         strncpy(typeName, &arrName[1], (int)arrName[0]);
1111                         typeName[(int)arrName[0]] = '\0';
1112                                 
1113                         int high = arrLen / lastType->getSize();
1114                         newType = new BPatch_type(typeName, -1, BPatch_array, lastType, 
1115                                                         0, high-1);
1116                 }
1117                 break;
1118         case LF_CLASS:
1119         case LF_STRUCTURE:
1120         {
1121                 int classLen;
1122                 char *className;
1123                 if ( ((LFClass *)trec)->length < LF_NUMERIC ) {
1124                         classLen = ((LFClass *)trec)->length;
1125                         className = (char *) ((LFClass *)trec)->name;
1126                 }
1127                 else {
1128                         //Need to calculate classLen
1129                         classLen = 0;
1130                         className = ( (char *) &((LFClass *)trec)->length ) +
1131                                                                         sizeof(DWORD);
1132                 }
1133                 strncpy(typeName, &className[1], (int)className[0]);
1134                 typeName[(int)className[0]] = '\0';
1135                                 
1136                 if (trec->leaf == LF_CLASS)
1137                         newType = new BPatch_type(typeName, -1, BPatch_dataTypeClass, classLen);
1138                 else
1139                         newType = new BPatch_type(typeName, -1, BPatch_dataStructure,
1140                                                                         classLen);
1141                 // printf("Name of the structure %s\n", typeName);
1142                 FindFields(mod, newType, ((LFClass *)trec)->count, 
1143                                         ((LFClass *)trec)->field, pTypeBase, startAddr);
1144                 break;
1145         }
1146         case LF_UNION:
1147         {
1148                 int unionLen;
1149                 char *unionName;
1150                 if ( ((LFUnion *)trec)->length < LF_NUMERIC ) {
1151                         unionLen = ((LFUnion *)trec)->length;
1152                         unionName = (char *) ((LFUnion *)trec)->name;
1153                 }
1154                 else {
1155                         //Need to calculate classLen
1156                         unionLen = 0;
1157                         unionName = ( (char *) &((LFUnion *)trec)->length ) +
1158                                                                         sizeof(DWORD);
1159                 }
1160                 strncpy(typeName, &unionName[1], (int)unionName[0]);
1161                 typeName[(int)unionName[0]] = '\0';
1162                                 
1163                 newType = new BPatch_type(typeName, -1, BPatch_union, unionLen);
1164                 FindFields(mod, newType, ((LFClass *)trec)->count,
1165                                 ((LFClass *)trec)->field, pTypeBase, startAddr);
1166                 break;
1167         }
1168         case LF_ENUM:
1169         {
1170                 strncpy(typeName, &((LFEnum *)trec)->name[1], 
1171                                                 (int)((LFEnum *)trec)->name[0]);
1172                 typeName[(int)((LFEnum *)trec)->name[0]] = '\0';
1173
1174                 newType = new BPatch_type(typeName, -1, BPatch_enumerated);
1175                 FindFields(mod, newType, ((LFEnum *)trec)->count,
1176                                 ((LFEnum *)trec)->fList, pTypeBase, startAddr);
1177                 break;
1178         }
1179         default:
1180                 break;
1181         }
1182
1183         if (!newType)
1184                 return NULL;
1185
1186         newType->setID(index);
1187         mod->moduleTypes->addType(newType);
1188         return(newType);
1189 }
1190 #endif // BPATCH_LIBRARY
1191
1192 //---------------------------------------------------------------------------
1193 // CodeView::Module methods
1194 //---------------------------------------------------------------------------
1195
1196 // a zero-argument constructor is required by the vector class
1197 CodeView::Module::Module( void )
1198   : pmod( NULL ),
1199         pas( NULL ),
1200         psrc( NULL ),
1201     offsetText( 0 ),
1202     cbText( 0 )
1203 {
1204 }
1205
1206
1207 CodeView::Module::Module( CodeView::ModuleSubsection* pModule,
1208                           unsigned int textId )
1209   : pmod( pModule ),
1210         pas( NULL ),
1211         psrc( NULL ),
1212     offsetText( 0 ),
1213     cbText( 0 )
1214 {
1215     // A module may contribute code to several segments (sections)
1216     // in the image.  Paradyn assumes that the .text section
1217     // is the only one that matters with respect to code, so
1218     // we provide the offset of the code from this module
1219     // in the  section.
1220         unsigned int i;
1221         bool found = false;
1222
1223
1224         // search the module subsection's segInfo array to find
1225         // the offset for the code from this module in the .text section
1226         const CodeView::ModuleSubsection::SegInfo* pSects = 
1227                 (const CodeView::ModuleSubsection::SegInfo*)(((const char*)pmod) 
1228             + sizeof(ModuleSubsection));
1229         for( i = 0; i < pmod->cSeg; i++ )
1230         {
1231                 if( pSects[i].seg == textId )
1232                 {
1233                         offsetText = pSects[i].offset;
1234                         cbText = pSects[i].cbSeg;
1235
1236 #ifdef _DEBUG
1237                         // check whether there are other ranges that 
1238                         // this module contributes to in the text segment
1239                         unsigned int j;
1240                         for( j = i + 1; j < pmod->cSeg; j++ )
1241                         {
1242                                 if( pSects[j].seg == textId )
1243                                 {
1244                                         cout << 
1245                         "warning: multiple contributions to text section"
1246                         << endl;
1247                                 }
1248                         }
1249 #endif // _DEBUG
1250             break;
1251                 }
1252         }
1253 }
1254
1255
1256 CodeView::Module&
1257 CodeView::Module::operator=( const CodeView::Module& mod )
1258 {
1259         if( &mod != this )
1260         {
1261                 pmod = mod.pmod;                        // sstModule subsection
1262                 pas = mod.pas;                          // sstAlignSym subsection
1263                 psrc = mod.psrc;                        // sstSrcModule subsection
1264                 syms = mod.syms;                        // symbols from the sstAlignSym subsection
1265
1266         offsetText = mod.offsetText;
1267         cbText = mod.cbText;
1268         }
1269         return *this;
1270 }
1271
1272
1273 string
1274 CodeView::Module::GetName( void ) const
1275 {
1276         LPString lpsName( ((char*)pmod) +
1277                 sizeof(ModuleSubsection) +
1278                 pmod->cSeg * sizeof( ModuleSubsection::SegInfo ) );
1279         return (string)lpsName;
1280 }
1281
1282
1283 // note that although the sstSrcModule subsection may 
1284 // indicate more than one source file contributed to the code
1285 // in this module, we always only consider the first
1286 // (Paradyn is not designed to handle more than one source
1287 // file per module, and the first source file seems to be
1288 // the "main" source file for the module)
1289 string
1290 CodeView::Module::GetSourceName( void ) const
1291 {
1292         // verify that we have a source file information for this module
1293         if( psrc == NULL )
1294         {
1295                 return "";
1296         }
1297
1298         // parse the sstSrcModule subsection to extract the first
1299         // source file name
1300         const char* curr = (const char*)psrc;
1301
1302         //
1303         // skip over the header...
1304         //
1305     // skip over file and segment counts
1306         assert( psrc->cFile > 0 );
1307     curr += 2 * sizeof( WORD );
1308
1309         // ...skip over the baseSrcFile table...
1310         curr += (psrc->cFile * sizeof( DWORD ));
1311
1312         // ...skip over the start/end table...
1313         curr += (psrc->cSeg * 2 * sizeof( DWORD ));
1314
1315         // ...skip over the seg table...
1316         curr += (psrc->cSeg * sizeof( WORD ));
1317         if( (psrc->cSeg % 2) != 0 )
1318         {
1319                 // skip alignment padding
1320                 curr += sizeof(WORD);
1321         }
1322
1323         //
1324         // we're now pointing at the information for the first source file
1325         //
1326     SrcModuleSubsection::FileInfo* fi = (SrcModuleSubsection::FileInfo*)curr;
1327         curr += sizeof( WORD );
1328
1329         // skip padding
1330         curr += sizeof(WORD);
1331
1332         // skip the line number/address mapping offset table
1333         curr += (fi->cSegFile * sizeof( DWORD ));
1334
1335         // skip over the start/end offset table
1336         curr += (fi->cSegFile * 2 * sizeof( DWORD ));
1337
1338         // we're now at the source file name
1339         // length in chars in the first byte, then the source file name chars
1340         LPString lpsName( curr );
1341         return lpsName;
1342 }
1343
1344
1345 // A module may contribute code to several segments (sections)
1346 // in the image.  Paradyn assumes that the .text section
1347 // is the only one that matters with respect to code, so
1348 // we provide the offset of the code from this module
1349 // in the  section.
1350 bool
1351 CodeView::Module::GetTextBounds( DWORD& offset, DWORD& cb ) const
1352 {
1353     bool ret = false;
1354
1355     if( cbText != 0 )
1356     {
1357         offset = offsetText;
1358         cb = cbText;
1359         ret = true;
1360     }
1361     return ret;
1362 }
1363