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