Added support for using CodeView NB11 symbols in addition to COFF
[dyninst.git] / pdutil / 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 #include <windows.h>
42 #include <imagehlp.h>
43 #include <assert.h>
44
45 #include <iostream.h>
46 #include <iomanip.h>
47
48 #include "util/h/String.h"
49 #include "util/h/Vector.h"
50 #include "util/h/CodeView.h"
51
52
53 //---------------------------------------------------------------------------
54 // CodeView methods
55 //---------------------------------------------------------------------------
56
57 bool
58 CodeView::Parse( void )
59 {
60         DWORD i;
61
62
63         // verify the CodeView signature
64         // currently, we only support the NB11 format
65         if( strncmp( pBase, "NB11", 4 ) != 0 )
66         {
67                 // indicate that we do not understand this CodeView format
68                 return false;
69         }
70
71         // obtain access to the subsection directory
72         SDHeader* pSDHdr = (SDHeader*)(pBase + *(DWORD*)(pBase + 4));
73
74         // parse the subsections, extracting the information we need
75         for( i = 0; i < pSDHdr->cDir; i++ )
76         {
77                 SDEntry* pEntry = 
78                         (SDEntry*)(((char*)pSDHdr) +
79                 pSDHdr->cbDirHeader + i * pSDHdr->cbDirEntry);
80
81                 switch( pEntry->sst )
82                 {
83                 case sstModule:
84                         ParseModuleSubsection( pEntry );
85                         break;
86
87                 case sstLibraries:
88                         ParseLibrariesSubsection( pEntry );
89                         break;
90
91                 case sstAlignSym:
92                         ParseAlignSymSubsection( pEntry );
93                         break;
94
95                 case sstSrcModule:
96                         ParseSrcModuleSubsection( pEntry );
97                         break;
98
99                 case sstGlobalPub:
100                 case sstStaticSym:
101                 case sstGlobalSym:
102                         ParseSymbolsWithHeaderSubsection( pEntry );
103                         break;
104
105                 default:
106                         // it is a subsection type we do not care about - skip it
107                         break;
108                 }
109         }
110
111         return true;
112 }
113
114
115
116 void
117 CodeView::ParseModuleSubsection( SDEntry* pEntry )
118 {
119         // ensure that the modules vector contains an element for this module
120         // recall that the modules vector uses a one-based index
121         if( pEntry->iMod >= modules.size() )
122         {
123                 modules.resize( pEntry->iMod + 1 );
124         }
125
126         // make a new entry for this module, starting with this module subsection
127         modules[pEntry->iMod] =
128         Module((ModuleSubsection*)(pBase + pEntry->offset), textId );
129 }
130
131
132 void
133 CodeView::ParseLibrariesSubsection( SDEntry* pEntry )
134 {
135         const char* curr = pBase + pEntry->offset;
136
137         while( curr < (pBase + pEntry->offset + pEntry->cb) )
138         {
139                 // add an entry for this library
140                 libs += curr;
141
142                 // advance to the next string
143                 curr += (*curr + 1);
144         }
145 }
146
147
148 void
149 CodeView::ParseSymbolsWithHeaderSubsection( SDEntry* pEntry )
150 {
151         SymHeader* pSymHdr = (SymHeader*)(pBase + pEntry->offset);
152
153         syms.Parse( ((char*)pSymHdr) + sizeof(SymHeader), pSymHdr->cbSymbol );
154 }
155
156
157 void
158 CodeView::ParseAlignSymSubsection( SDEntry* pEntry )
159 {
160         // associate this subsection with the correct module
161         Module& mod = modules[pEntry->iMod];
162         mod.pas = (AlignSymSubsection*)(pBase + pEntry->offset);
163
164         // parse the symbols represented in this section
165         mod.syms.Parse( (const char*)mod.pas, pEntry->cb );
166 }
167
168
169 void
170 CodeView::ParseSrcModuleSubsection( SDEntry* pEntry )
171 {
172         // associate this subsection with the correct module
173         Module& mod = modules[pEntry->iMod];
174         mod.psrc = (SrcModuleSubsection*)(pBase + pEntry->offset);
175 }
176
177
178
179 //---------------------------------------------------------------------------
180 // CodeView::Symbols methods
181 //---------------------------------------------------------------------------
182
183
184 void
185 CodeView::Symbols::Parse( const char* pSymBase, DWORD cb )
186 {
187         // scan the symbols linearly
188         SymRecord* curr = (SymRecord*)pSymBase;
189         while( ((char*)curr) < (pSymBase + cb) )
190         {
191
192                 // handle the symbol record
193                 switch( curr->index )
194                 {
195                 case S_LPROC32:
196                         // add the entry to our list of functions
197                         lprocs += ( (SymRecordProc*)curr );
198                         break;
199
200                 case S_GPROC32:
201                         // add the entry to our list of functions
202                         gprocs += ( (SymRecordProc*)curr );
203                         break;
204
205                 case S_LDATA32:
206                         // add the entry to our list of variables
207                         lvars += ( (SymRecordData*)curr );
208                         break;
209
210                 case S_GDATA32:
211                         // add the entry to our list of variables
212                         gvars += ( (SymRecordData*)curr );
213                         break;
214
215                 case S_LABEL32:
216                         labels += ( (SymRecordLabel*)curr );
217                         break;
218
219                 case S_BPREL32:
220                         bprels += ( (SymRecordBPRel*)curr );
221                         break;
222
223                 case S_THUNK32:
224                         thunks += ( (SymRecordThunk*)curr );
225                         break;
226
227                 case S_END:
228                         // nothing to do for end markers
229                         break;
230
231                 case S_ALIGN:
232                         // skip padding records
233                         break;
234
235         case S_PUB32:
236             pubs += (SymRecordData*)curr;
237             break;
238
239                 default:
240                         // it is a record type that we do not care about
241                         break;
242                 }
243
244                 // advance to the next symbol
245                 curr = (SymRecord*)(((char*)curr) + curr->length + sizeof(WORD));
246         }
247 }
248
249
250
251 CodeView::Symbols&
252 CodeView::Symbols::operator=( const CodeView::Symbols& syms )
253 {
254         if( &syms != this )
255         {
256                 gprocs = syms.gprocs;           // global functions
257                 lprocs = syms.lprocs;           // local functions
258                 gvars = syms.gvars;                     // global variables
259                 lvars = syms.lvars;                     // local variables
260                 bprels = syms.bprels;           // stack variables
261                 labels = syms.labels;           // labels
262                 thunks = syms.thunks;           // thunks (code outside of functions)
263         pubs = syms.pubs;           // public (catch-all) symbols
264         }
265         return *this;
266 }
267
268
269
270 //---------------------------------------------------------------------------
271 // CodeView::Module methods
272 //---------------------------------------------------------------------------
273
274 // a zero-argument constructor is required by the vector class
275 CodeView::Module::Module( void )
276   : pmod( NULL ),
277         pas( NULL ),
278         psrc( NULL ),
279     offsetText( 0 ),
280     cbText( 0 )
281 {
282 }
283
284
285 CodeView::Module::Module( CodeView::ModuleSubsection* pModule,
286                           unsigned int textId )
287   : pmod( pModule ),
288         pas( NULL ),
289         psrc( NULL ),
290     offsetText( 0 ),
291     cbText( 0 )
292 {
293     // A module may contribute code to several segments (sections)
294     // in the image.  Paradyn assumes that the .text section
295     // is the only one that matters with respect to code, so
296     // we provide the offset of the code from this module
297     // in the  section.
298         unsigned int i;
299         bool found = false;
300
301
302         // search the module subsection's segInfo array to find
303         // the offset for the code from this module in the .text section
304         const CodeView::ModuleSubsection::SegInfo* pSects = 
305                 (const CodeView::ModuleSubsection::SegInfo*)(((const char*)pmod) 
306             + sizeof(ModuleSubsection));
307         for( i = 0; i < pmod->cSeg; i++ )
308         {
309                 if( pSects[i].seg == textId )
310                 {
311                         offsetText = pSects[i].offset;
312                         cbText = pSects[i].cbSeg;
313
314 #ifdef _DEBUG
315                         // check whether there are other ranges that 
316                         // this module contributes to in the text segment
317                         unsigned int j;
318                         for( j = i + 1; j < pmod->cSeg; j++ )
319                         {
320                                 if( pSects[j].seg == textId )
321                                 {
322                                         cout << 
323                         "warning: multiple contributions to text section"
324                         << endl;
325                                 }
326                         }
327 #endif // _DEBUG
328             break;
329                 }
330         }
331 }
332
333
334 CodeView::Module&
335 CodeView::Module::operator=( const CodeView::Module& mod )
336 {
337         if( &mod != this )
338         {
339                 pmod = mod.pmod;                        // sstModule subsection
340                 pas = mod.pas;                          // sstAlignSym subsection
341                 psrc = mod.psrc;                        // sstSrcModule subsection
342                 syms = mod.syms;                        // symbols from the sstAlignSym subsection
343
344         offsetText = mod.offsetText;
345         cbText = mod.cbText;
346         }
347         return *this;
348 }
349
350
351 string
352 CodeView::Module::GetName( void ) const
353 {
354         LPString lpsName( ((char*)pmod) +
355                 sizeof(ModuleSubsection) +
356                 pmod->cSeg * sizeof( ModuleSubsection::SegInfo ) );
357         return (string)lpsName;
358 }
359
360
361 // note that although the sstSrcModule subsection may 
362 // indicate more than one source file contributed to the code
363 // in this module, we always only consider the first
364 // (Paradyn is not designed to handle more than one source
365 // file per module, and the first source file seems to be
366 // the "main" source file for the module)
367 string
368 CodeView::Module::GetSourceName( void ) const
369 {
370         // verify that we have a source file information for this module
371         if( psrc == NULL )
372         {
373                 return "";
374         }
375
376         // parse the sstSrcModule subsection to extract the first
377         // source file name
378         const char* curr = (const char*)psrc;
379
380         //
381         // skip over the header...
382         //
383     // skip over file and segment counts
384         assert( psrc->cFile > 0 );
385     curr += 2 * sizeof( WORD );
386
387         // ...skip over the baseSrcFile table...
388         curr += (psrc->cFile * sizeof( DWORD ));
389
390         // ...skip over the start/end table...
391         curr += (psrc->cSeg * 2 * sizeof( DWORD ));
392
393         // ...skip over the seg table...
394         curr += (psrc->cSeg * sizeof( WORD ));
395         if( (psrc->cSeg % 2) != 0 )
396         {
397                 // skip alignment padding
398                 curr += sizeof(WORD);
399         }
400
401         //
402         // we're now pointing at the information for the first source file
403         //
404     SrcModuleSubsection::FileInfo* fi = (SrcModuleSubsection::FileInfo*)curr;
405         curr += sizeof( WORD );
406
407         // skip padding
408         curr += sizeof(WORD);
409
410         // skip the line number/address mapping offset table
411         curr += (fi->cSegFile * sizeof( DWORD ));
412
413         // skip over the start/end offset table
414         curr += (fi->cSegFile * 2 * sizeof( DWORD ));
415
416         // we're now at the source file name
417         // length in chars in the first byte, then the source file name chars
418         LPString lpsName( curr );
419         return lpsName;
420 }
421
422
423 // A module may contribute code to several segments (sections)
424 // in the image.  Paradyn assumes that the .text section
425 // is the only one that matters with respect to code, so
426 // we provide the offset of the code from this module
427 // in the  section.
428 bool
429 CodeView::Module::GetTextBounds( DWORD& offset, DWORD& cb ) const
430 {
431     bool ret = false;
432
433     if( cbText != 0 )
434     {
435         offset = offsetText;
436         cb = cbText;
437         ret = true;
438     }
439     return ret;
440 }
441
442