Moved the debugger to programs/winedbg where it belongs.
[wine] / programs / winedbg / 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  void*   DEBUG_MapFile(const char* name, HANDLE* hMap, unsigned* size)
110 {
111     HANDLE              hFile;
112
113     hFile = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL,
114                        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
115     if (hFile == INVALID_HANDLE_VALUE) return (void*)-1;
116     if (size != NULL && (*size = GetFileSize(hFile, NULL)) == -1) return (void*)-1;
117     *hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
118     CloseHandle(hFile);
119     if (!*hMap) return (void*)-1;
120     return MapViewOfFile(*hMap, FILE_MAP_READ, 0, 0, 0);
121 }
122
123 static void     DEBUG_UnmapFile(void* addr, HANDLE hMap)
124 {
125     UnmapViewOfFile(addr);
126     CloseHandle(hMap);
127 }
128
129 static struct open_filelist*    DEBUG_SearchOpenFile(const char* name)
130 {
131     struct open_filelist*       ol;
132
133     for (ol = ofiles; ol; ol = ol->next)
134     {
135         if (strcmp(ol->path, name) == 0) break;
136     }
137     return ol;
138 }
139
140 static
141 int
142 DEBUG_DisplaySource(char * sourcefile, int start, int end)
143 {
144     char*                       addr;
145     int                         i;
146     struct open_filelist*       ol;
147     int                         nlines;
148     char*                       basename = NULL;
149     char*                       pnt;
150     int                         rtn;
151     struct searchlist*          sl;
152     HANDLE                      hMap;
153     DWORD                       status;
154     char                        tmppath[PATH_MAX];
155
156     /*
157      * First see whether we have the file open already.  If so, then
158      * use that, otherwise we have to try and open it.
159      */
160     ol = DEBUG_SearchOpenFile(sourcefile);
161
162     if ( ol == NULL )
163     {
164         /*
165          * Try again, stripping the path from the opened file.
166          */
167         basename = strrchr(sourcefile, '\\' );
168         if ( !basename )
169             basename = strrchr(sourcefile, '/' );
170         if ( !basename )
171             basename = sourcefile;
172         else
173             basename++;
174
175         ol = DEBUG_SearchOpenFile(basename);
176     }
177
178     if ( ol == NULL )
179     {
180         /*
181          * Crapola.  We need to try and open the file.
182          */
183         status = GetFileAttributes(sourcefile);
184         if ( status != -1 )
185         {
186             strcpy(tmppath, sourcefile);
187         }
188         else if ( (status = GetFileAttributes(basename)) != -1 )
189         {
190             strcpy(tmppath, basename);
191         }
192         else
193         {
194             for (sl = listhead; sl; sl = sl->next)
195             {
196                 strcpy(tmppath, sl->path);
197                 if ( tmppath[strlen(tmppath)-1] != '/' && 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 = GetFileAttributes(tmppath);
207                 if ( status != -1 ) break;
208             }
209
210             if ( sl == NULL )
211             {
212                 if (DEBUG_InteractiveP)
213                 {
214                     char zbuf[256];
215                     /*
216                      * Still couldn't find it.  Ask user for path to add.
217                      */
218                     sprintf(zbuf, "Enter path to file '%s': ", sourcefile);
219                     DEBUG_ReadLine(zbuf, tmppath, sizeof(tmppath));
220
221                     if ( tmppath[strlen(tmppath)-1] != '/' )
222                     {
223                         strcat(tmppath, "/");
224                     }
225                     /*
226                      * Now append the base file name.
227                      */
228                     strcat(tmppath, basename);
229
230                     status = GetFileAttributes(tmppath);
231                 }
232                 else
233                 {
234                     status = -1;
235                     strcpy(tmppath, sourcefile);
236                 }
237
238                 if ( status == -1 )
239                 {
240                     /*
241                      * OK, I guess the user doesn't really want to see it
242                      * after all.
243                      */
244                     ol = (struct open_filelist *) DBG_alloc(sizeof(*ol));
245                     ol->path = DBG_strdup(sourcefile);
246                     ol->real_path = NULL;
247                     ol->next = ofiles;
248                     ol->nlines = 0;
249                     ol->linelist = NULL;
250                     ofiles = ol;
251                     DEBUG_Printf(DBG_CHN_MESG,"Unable to open file %s\n", tmppath);
252                     return FALSE;
253                 }
254             }
255         }
256         /*
257          * Create header for file.
258          */
259         ol = (struct open_filelist *) DBG_alloc(sizeof(*ol));
260         ol->path = DBG_strdup(sourcefile);
261         ol->real_path = DBG_strdup(tmppath);
262         ol->next = ofiles;
263         ol->nlines = 0;
264         ol->linelist = NULL;
265         ol->size = 0;
266         ofiles = ol;
267
268         addr = DEBUG_MapFile(tmppath, &hMap, &ol->size);
269         if ( addr == (char *) -1 )
270         {
271             return FALSE;
272         }
273         /*
274          * Now build up the line number mapping table.
275          */
276         ol->nlines = 1;
277         pnt = addr;
278         while (pnt < addr + ol->size )
279         {
280             if ( *pnt++ == '\n' )
281             {
282                 ol->nlines++;
283             }
284         }
285
286         ol->nlines++;
287         ol->linelist = (unsigned int*) DBG_alloc( ol->nlines * sizeof(unsigned int) );
288
289         nlines = 0;
290         pnt = addr;
291         ol->linelist[nlines++] = 0;
292         while(pnt < addr + ol->size )
293         {
294             if( *pnt++ == '\n' )
295             {
296                 ol->linelist[nlines++] = pnt - addr;
297             }
298         }
299         ol->linelist[nlines++] = pnt - addr;
300
301     }
302     else
303     {
304         addr = DEBUG_MapFile(ol->real_path, &hMap, NULL);
305         if ( addr == (char *) -1 )
306         {
307             return FALSE;
308         }
309     }
310     /*
311      * All we need to do is to display the source lines here.
312      */
313     rtn = FALSE;
314     for (i = start - 1; i <= end - 1; i++)
315     {
316         char    buffer[1024];
317
318         if (i < 0 || i >= ol->nlines - 1)
319         {
320             continue;
321         }
322
323         rtn = TRUE;
324         memset(&buffer, 0, sizeof(buffer));
325         if ( ol->linelist[i+1] != ol->linelist[i] )
326         {
327             memcpy(&buffer, addr + ol->linelist[i],
328                    (ol->linelist[i+1] - ol->linelist[i]) - 1);
329         }
330         DEBUG_Printf(DBG_CHN_MESG,"%d\t%s\n", i + 1,  buffer);
331     }
332
333     DEBUG_UnmapFile(addr, hMap);
334     return rtn;
335 }
336
337 void
338 DEBUG_List(struct list_id * source1, struct list_id * source2,
339                          int delta)
340 {
341   int    end;
342   int    rtn;
343   int    start;
344   char * sourcefile;
345
346   /*
347    * We need to see what source file we need.  Hopefully we only have
348    * one specified, otherwise we might as well punt.
349    */
350   if( source1 != NULL
351       && source2 != NULL
352       && source1->sourcefile != NULL
353       && source2->sourcefile != NULL
354       && strcmp(source1->sourcefile, source2->sourcefile) != 0 )
355     {
356       DEBUG_Printf(DBG_CHN_MESG, "Ambiguous source file specification.\n");
357       return;
358     }
359
360   sourcefile = NULL;
361   if( source1 != NULL && source1->sourcefile != NULL )
362     {
363       sourcefile = source1->sourcefile;
364     }
365
366   if( sourcefile == NULL
367       && source2 != NULL
368       && source2->sourcefile != NULL )
369     {
370       sourcefile = source2->sourcefile;
371     }
372
373   if( sourcefile == NULL )
374     {
375       sourcefile = (char *) &DEBUG_current_sourcefile;
376     }
377
378   if( sourcefile == NULL )
379     {
380       DEBUG_Printf(DBG_CHN_MESG, "No source file specified.\n");
381       return;
382     }
383
384   /*
385    * Now figure out the line number range to be listed.
386    */
387   start = -1;
388   end = -1;
389
390   if( source1 != NULL )
391     {
392       start = source1->line;
393     }
394
395   if( source2 != NULL )
396     {
397       end = source2->line;
398     }
399
400   if( start == -1 && end == -1 )
401     {
402       if( delta < 0 )
403         {
404           end = DEBUG_start_sourceline;
405           start = end + delta;
406         }
407       else
408         {
409           start = DEBUG_end_sourceline;
410           end = start + delta;
411         }
412     }
413   else if( start == -1 )
414     {
415       start = end + delta;
416     }
417   else if (end == -1)
418     {
419       end = start + delta;
420     }
421
422   /*
423    * Now call this function to do the dirty work.
424    */
425   rtn = DEBUG_DisplaySource(sourcefile, start, end);
426
427   if( sourcefile != (char *) &DEBUG_current_sourcefile )
428     {
429       strcpy(DEBUG_current_sourcefile, sourcefile);
430     }
431   DEBUG_start_sourceline = start;
432   DEBUG_end_sourceline = end;
433 }
434
435 DBG_ADDR DEBUG_LastDisassemble={0,0};
436
437 BOOL DEBUG_DisassembleInstruction(DBG_ADDR *addr)
438 {
439    char         ch;
440    BOOL         ret = TRUE;
441
442    DEBUG_PrintAddress(addr, DEBUG_CurrThread->dbg_mode, TRUE);
443    DEBUG_Printf(DBG_CHN_MESG, ": ");
444    if (!DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear(addr), &ch, sizeof(ch))) {
445       DEBUG_Printf(DBG_CHN_MESG, "-- no code --");
446       ret = FALSE;
447    } else {
448       DEBUG_Disasm(addr, TRUE);
449    }
450    DEBUG_Printf(DBG_CHN_MESG,"\n");
451    return ret;
452 }
453
454 void
455 DEBUG_Disassemble(const DBG_VALUE *xstart,const DBG_VALUE *xend,int offset)
456 {
457   int i;
458   DBG_ADDR      last;
459   DBG_VALUE     end,start;
460
461   if (xstart) {
462     start = *xstart;
463     DEBUG_GrabAddress(&start, TRUE);
464   }
465   if (xend) {
466     end = *xend;
467     DEBUG_GrabAddress(&end, TRUE);
468   }
469   if (!xstart && !xend) {
470     last = DEBUG_LastDisassemble;
471     if (!last.seg && !last.off)
472       DEBUG_GetCurrentAddress( &last );
473
474     for (i=0;i<offset;i++)
475       if (!DEBUG_DisassembleInstruction(&last)) break;
476     DEBUG_LastDisassemble = last;
477     return;
478   }
479   last = start.addr;
480   if (!xend) {
481     for (i=0;i<offset;i++)
482       if (!DEBUG_DisassembleInstruction(&last)) break;
483     DEBUG_LastDisassemble = last;
484     return;
485   }
486   while (last.off <= end.addr.off)
487     if (!DEBUG_DisassembleInstruction(&last)) break;
488   DEBUG_LastDisassemble = last;
489   return;
490 }