More portable signature check.
[wine] / debugger / source.c
1 /*
2  * File source.c - source file handling for internal debugger.
3  *
4  * Copyright (C) 1997, Eric Youngdale.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library 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 GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include <sys/types.h>
26 #ifdef HAVE_SYS_MMAN_H
27 #include <sys/mman.h>
28 #endif
29 #include <fcntl.h>
30 #include <sys/stat.h>
31 #include <limits.h>
32 #include <string.h>
33 #include <unistd.h>
34 #ifndef PATH_MAX
35 #define PATH_MAX _MAX_PATH
36 #endif
37
38 #include "debugger.h"
39
40 struct searchlist
41 {
42   char * path;
43   struct searchlist * next;
44 };
45
46
47 struct open_filelist
48 {
49   char                  * path;
50   char                  * real_path;
51   struct open_filelist  * next;
52   unsigned int            size;
53   signed int              nlines;
54   unsigned int          * linelist;
55 };
56
57 static struct open_filelist * ofiles;
58
59 static struct searchlist * listhead;
60 static char DEBUG_current_sourcefile[PATH_MAX];
61 static int DEBUG_start_sourceline = -1;
62 static int DEBUG_end_sourceline = -1;
63
64 void
65 DEBUG_ShowDir(void)
66 {
67   struct searchlist * sl;
68
69   DEBUG_Printf(DBG_CHN_MESG,"Search list :\n");
70   for(sl = listhead; sl; sl = sl->next)
71     {
72       DEBUG_Printf(DBG_CHN_MESG, "\t%s\n", sl->path);
73     }
74   DEBUG_Printf(DBG_CHN_MESG, "\n");
75 }
76
77 void
78 DEBUG_AddPath(const char * path)
79 {
80   struct searchlist * sl;
81
82   sl = (struct searchlist *) DBG_alloc(sizeof(struct searchlist));
83   if( sl == NULL )
84     {
85       return;
86     }
87
88   sl->next = listhead;
89   sl->path = DBG_strdup(path);
90   listhead = sl;
91 }
92
93 void
94 DEBUG_NukePath(void)
95 {
96   struct searchlist * sl;
97   struct searchlist * nxt;
98
99   for(sl = listhead; sl; sl = nxt)
100     {
101       nxt = sl->next;
102       DBG_free(sl->path);
103       DBG_free(sl);
104     }
105
106   listhead = NULL;
107 }
108
109 static
110 int
111 DEBUG_DisplaySource(char * sourcefile, int start, int end)
112 {
113   char                        * addr;
114   char                          buffer[1024];
115   int                           fd;
116   int                           i;
117   struct open_filelist        * ol;
118   int                           nlines;
119   char                        * basename = NULL;
120   char                        * pnt;
121   int                           rtn;
122   struct searchlist           * sl;
123   struct stat                   statbuf;
124   int                           status;
125   char                          tmppath[PATH_MAX];
126
127   /*
128    * First see whether we have the file open already.  If so, then
129    * use that, otherwise we have to try and open it.
130    */
131   for(ol = ofiles; ol; ol = ol->next)
132     {
133       if( strcmp(ol->path, sourcefile) == 0 )
134         {
135           break;
136         }
137     }
138
139   if( ol == NULL )
140     {
141       /*
142        * Try again, stripping the path from the opened file.
143        */
144       basename = strrchr(sourcefile, '\\' );
145       if ( !basename )
146           basename = strrchr(sourcefile, '/' );
147       if ( !basename )
148           basename = sourcefile;
149       else
150           basename++;
151
152       for(ol = ofiles; ol; ol = ol->next)
153         {
154           if( strcmp(ol->path, basename) == 0 )
155             {
156               break;
157             }
158         }
159       
160     }
161
162   if( ol == NULL )
163     {
164       /*
165        * Crapola.  We need to try and open the file.
166        */
167       status = stat(sourcefile, &statbuf);
168       if( status != -1 )
169         {
170           strcpy(tmppath, sourcefile);
171         }
172       else if( (status = stat(basename, &statbuf)) != -1 )
173         {
174           strcpy(tmppath, basename);
175         }
176       else
177         {
178           for(sl = listhead; sl; sl = sl->next)
179             {
180               strcpy(tmppath, sl->path);
181               if( tmppath[strlen(tmppath)-1] != '/' )
182                 {
183                   strcat(tmppath, "/");
184                 }
185               /*
186                * Now append the base file name.
187                */
188               strcat(tmppath, basename);
189               
190               status = stat(tmppath, &statbuf);
191               if( status != -1 )
192                 {
193                   break;
194                 }
195             }
196           
197           if( sl == NULL )
198             {
199               char      zbuf[256];
200               /*
201                * Still couldn't find it.  Ask user for path to add.
202                */
203               sprintf(zbuf, "Enter path to file '%s': ", sourcefile);
204               DEBUG_ReadLine(zbuf, tmppath, sizeof(tmppath), FALSE, FALSE);
205               
206               if( tmppath[strlen(tmppath)-1] == '\n' )
207                 {
208                   tmppath[strlen(tmppath)-1] = '\0';
209                 }
210               
211               if( tmppath[strlen(tmppath)-1] != '/' )
212                 {
213                   strcat(tmppath, "/");
214                 }
215               /*
216                * Now append the base file name.
217                */
218               strcat(tmppath, basename);
219               
220               status = stat(tmppath, &statbuf);
221               if( status == -1 )
222                 {
223                   /*
224                    * OK, I guess the user doesn't really want to see it
225                    * after all.
226                    */
227                   ol = (struct open_filelist *) DBG_alloc(sizeof(*ol));
228                   ol->path = DBG_strdup(sourcefile);
229                   ol->real_path = NULL;
230                   ol->next = ofiles;
231                   ol->nlines = 0;
232                   ol->linelist = NULL;
233                   ofiles = ol;
234                   DEBUG_Printf(DBG_CHN_MESG,"Unable to open file %s\n", tmppath);
235                   return FALSE;
236                 }
237             }
238         }
239       /*
240        * Create header for file.
241        */
242       ol = (struct open_filelist *) DBG_alloc(sizeof(*ol));
243       ol->path = DBG_strdup(sourcefile);
244       ol->real_path = DBG_strdup(tmppath);
245       ol->next = ofiles;
246       ol->nlines = 0;
247       ol->linelist = NULL;
248       ol->size = statbuf.st_size;
249       ofiles = ol;
250
251       /*
252        * Now open and map the file.
253        */
254       fd = open(tmppath, O_RDONLY);
255       if( fd == -1 )
256         {
257           return FALSE;
258         }
259
260       addr = mmap(0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
261       if( addr == (char *) -1 )
262         {
263           return FALSE;
264         }
265
266       /*
267        * Now build up the line number mapping table.
268        */
269       ol->nlines = 1;
270       pnt = addr;
271       while(pnt < addr + ol->size )
272         {
273           if( *pnt++ == '\n' )
274             {
275               ol->nlines++;
276             }
277         }
278
279       ol->nlines++;
280       ol->linelist = (unsigned int*) DBG_alloc( ol->nlines * sizeof(unsigned int) );
281
282       nlines = 0;
283       pnt = addr;
284       ol->linelist[nlines++] = 0;
285       while(pnt < addr + ol->size )
286         {
287           if( *pnt++ == '\n' )
288             {
289               ol->linelist[nlines++] = pnt - addr;
290             }
291         }
292       ol->linelist[nlines++] = pnt - addr;
293
294     }
295   else
296     {
297       /*
298        * We know what the file is, we just need to reopen it and remap it.
299        */
300       fd = open(ol->real_path, O_RDONLY);
301       if( fd == -1 )
302         {
303           return FALSE;
304         }
305       
306       addr = mmap(0, ol->size, PROT_READ, MAP_PRIVATE, fd, 0);
307       if( addr == (char *) -1 )
308         {
309           return FALSE;
310         }
311     }
312   
313   /*
314    * All we need to do is to display the source lines here.
315    */
316   rtn = FALSE;
317   for(i=start - 1; i <= end - 1; i++)
318     {
319       if( i < 0 || i >= ol->nlines - 1)
320         {
321           continue;
322         }
323
324       rtn = TRUE;
325       memset(&buffer, 0, sizeof(buffer));
326       if( ol->linelist[i+1] != ol->linelist[i] )
327         {
328           memcpy(&buffer, addr + ol->linelist[i], 
329                  (ol->linelist[i+1] - ol->linelist[i]) - 1);
330         }
331       DEBUG_Printf(DBG_CHN_MESG,"%d\t%s\n", i + 1,  buffer);
332     }
333
334   munmap(addr, ol->size);
335   close(fd);
336
337   return rtn;
338
339 }
340
341 void
342 DEBUG_List(struct list_id * source1, struct list_id * source2,
343                          int delta)
344 {
345   int    end;
346   int    rtn;
347   int    start;
348   char * sourcefile;
349
350   /*
351    * We need to see what source file we need.  Hopefully we only have
352    * one specified, otherwise we might as well punt.
353    */
354   if( source1 != NULL 
355       && source2 != NULL 
356       && source1->sourcefile != NULL
357       && source2->sourcefile != NULL 
358       && strcmp(source1->sourcefile, source2->sourcefile) != 0 )
359     {
360       DEBUG_Printf(DBG_CHN_MESG, "Ambiguous source file specification.\n");
361       return;
362     }
363
364   sourcefile = NULL;
365   if( source1 != NULL && source1->sourcefile != NULL )
366     {
367       sourcefile = source1->sourcefile;
368     }
369
370   if( sourcefile == NULL 
371       && source2 != NULL 
372       && source2->sourcefile != NULL )
373     {
374       sourcefile = source2->sourcefile;
375     }
376
377   if( sourcefile == NULL )
378     {
379       sourcefile = (char *) &DEBUG_current_sourcefile;
380     }
381
382   if( sourcefile == NULL )
383     {
384       DEBUG_Printf(DBG_CHN_MESG, "No source file specified.\n");
385       return;
386     }
387
388   /*
389    * Now figure out the line number range to be listed.
390    */
391   start = -1;
392   end = -1;
393
394   if( source1 != NULL )
395     {
396       start = source1->line;
397     }
398
399   if( source2 != NULL )
400     {
401       end = source2->line;
402     }
403
404   if( start == -1 && end == -1 )
405     {
406       if( delta < 0 )
407         {
408           end = DEBUG_start_sourceline;
409           start = end + delta;
410         }
411       else
412         {
413           start = DEBUG_end_sourceline;
414           end = start + delta;
415         }
416     }
417   else if( start == -1 )
418     {
419       start = end + delta;
420     }
421   else if (end == -1)
422     {
423       end = start + delta;
424     }
425
426   /*
427    * Now call this function to do the dirty work.
428    */
429   rtn = DEBUG_DisplaySource(sourcefile, start, end);
430
431   if( sourcefile != (char *) &DEBUG_current_sourcefile )
432     {
433       strcpy(DEBUG_current_sourcefile, sourcefile);
434     }
435   DEBUG_start_sourceline = start;
436   DEBUG_end_sourceline = end;
437 }
438
439 DBG_ADDR DEBUG_LastDisassemble={0,0};
440
441 BOOL DEBUG_DisassembleInstruction(DBG_ADDR *addr)
442 {
443    char         ch;
444    BOOL         ret = TRUE;
445
446    DEBUG_PrintAddress(addr, DEBUG_CurrThread->dbg_mode, TRUE);
447    DEBUG_Printf(DBG_CHN_MESG, ": ");
448    if (!DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear(addr), &ch, sizeof(ch))) {
449       DEBUG_Printf(DBG_CHN_MESG, "-- no code --");
450       ret = FALSE;
451    } else {
452       DEBUG_Disasm(addr, TRUE);
453    }
454    DEBUG_Printf(DBG_CHN_MESG,"\n");
455    return ret;
456 }
457
458 void
459 DEBUG_Disassemble(const DBG_VALUE *xstart,const DBG_VALUE *xend,int offset)
460 {
461   int i;
462   DBG_ADDR      last;
463   DBG_VALUE     end,start;
464
465   if (xstart) {
466     start = *xstart;
467     DEBUG_GrabAddress(&start, TRUE);
468   }
469   if (xend) {
470     end = *xend;
471     DEBUG_GrabAddress(&end, TRUE);
472   }
473   if (!xstart && !xend) {
474     last = DEBUG_LastDisassemble;
475     if (!last.seg && !last.off)
476       DEBUG_GetCurrentAddress( &last );
477
478     for (i=0;i<offset;i++)
479       if (!DEBUG_DisassembleInstruction(&last)) break;
480     DEBUG_LastDisassemble = last;
481     return;
482   }
483   last = start.addr;
484   if (!xend) {
485     for (i=0;i<offset;i++)
486       if (!DEBUG_DisassembleInstruction(&last)) break;
487     DEBUG_LastDisassemble = last;
488     return;
489   }
490   while (last.off <= end.addr.off)
491     if (!DEBUG_DisassembleInstruction(&last)) break;
492   DEBUG_LastDisassemble = last;
493   return;
494 }
495