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