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