Better error messages.
[wine] / debugger / memory.c
1 /*
2  * Debugger memory handling
3  *
4  * Copyright 1993 Eric Youngdale
5  * Copyright 1995 Alexandre Julliard
6  */
7
8 #include "config.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include "wine/winbase16.h"
12 #include "debugger.h"
13 #include "miscemu.h"
14
15
16 /************************************************************
17  *   
18  *  Check if linear pointer in [addr, addr+size[
19  *     read  (rwflag == 1)
20  *   or
21  *     write (rwflag == 0)
22  ************************************************************/
23
24 BOOL DEBUG_checkmap_bad( const char *addr, size_t size, int rwflag)
25 {
26   FILE *fp;
27   char buf[200];      /* temporary line buffer */
28   char prot[5];      /* protection string */
29   char *start, *end;
30   int ret = TRUE;
31
32 #ifdef linux
33   /* 
34      The entries in /proc/self/maps are of the form:
35      08000000-08002000 r-xp 00000000 03:41 2361
36      08002000-08003000 rw-p 00001000 03:41 2361
37      08003000-08005000 rwxp 00000000 00:00 0
38      40000000-40005000 r-xp 00000000 03:41 67219
39      40005000-40006000 rw-p 00004000 03:41 67219
40      40006000-40007000 rw-p 00000000 00:00 0
41      ...
42       start    end     perm   ???    major:minor inode
43
44      Only permissions start and end are used here
45      */
46 #else
47 /*
48     % cat /proc/curproc/map
49     start      end         resident   private perm    type
50     0x1000     0xe000            12         0 r-x COW vnode
51     0xe000     0x10000            2         2 rwx COW vnode
52     0x10000    0x27000            4         4 rwx     default
53     0x800e000  0x800f000          1         1 rw-     default
54     0xefbde000 0xefbfe000         1         1 rwx     default
55     
56     COW = "copy on write"
57
58
59     % cat /proc/curproc/map on FreeBSD 3.0
60     start     end       ?  ?  ?      prot ? ? ?   ?   ?  ?
61     0x8048000 0x8054000 12 14 114770 r-x  2 1 0x0 COW NC vnode
62     0x8054000 0x8055000 1 0 166664 rwx 1 0 0x2180 COW NNC vnode
63     0x8055000 0x806a000 5 0 166662 rwx 1 0 0x2180 NCOW NNC default
64     0x28054000 0x28055000 1 0 166666 rwx 1 0 0x2180 NCOW NNC default
65     0xefbde000 0xefbfe000 1 0 166663 rwx 1 0 0x2180 NCOW NNC default
66
67 */
68 #endif
69
70   
71   if (!(fp = fopen("/proc/self/maps","r")) && 
72       !(fp = fopen("/proc/curproc/map","r"))
73   )
74     return FALSE; 
75
76 #ifdef __FreeBSD__
77   /*
78    * *FOO*  read(2) less than length of /proc/.../map fails with EFBIG
79    *
80    * $ dd bs=256 </proc/curproc/map 
81    * dd: stdin: File too large
82    * 0+0 records in
83    * 0+0 records out
84    * 0 bytes transferred in 0.001595 secs (0 bytes/sec)
85    */
86   setvbuf(fp, (char *)NULL, _IOFBF, 0x4000);
87 #endif
88   while (fgets( buf, sizeof(buf)-1, fp)) {
89 #ifdef linux
90     sscanf(buf, "%x-%x %3s", (int *) &start, (int *) &end, prot);
91 #else
92     sscanf(buf, "%x %x %*d %*d %3s", (int *) &start, (int *) &end, prot);
93     if (prot[0]!='r' && prot[0]!='-') /* FreeBSD 3.0 format */
94        sscanf(buf, "%x %x %*d %*d %*d %3s", (int *) &start, (int *) &end, prot);
95 #endif
96     if ( end <= addr)
97       continue;
98     if (start <= addr && addr+size <= end) {
99       if (rwflag) 
100         ret = (prot[0] != 'r'); /* test for reading */
101       else
102         ret = (prot[1] != 'w'); /* test for writing */
103     }
104     break;
105   }
106   fclose( fp);
107   return ret;
108 }
109
110
111 /***********************************************************************
112  *           DEBUG_IsBadReadPtr
113  *
114  * Check if we are allowed to read memory at 'address'.
115  */
116 BOOL DEBUG_IsBadReadPtr( const DBG_ADDR *address, int size )
117 {
118 #ifdef __i386__
119     if (!IS_SELECTOR_V86(address->seg))
120     if (address->seg)  /* segmented addr */
121     {
122         if (IsBadReadPtr16( (SEGPTR)MAKELONG( (WORD)address->off,
123                                               (WORD)address->seg ), size ))
124             return TRUE;
125     }
126 #endif
127     return DEBUG_checkmap_bad( DBG_ADDR_TO_LIN(address), size, 1);
128 }
129
130
131 /***********************************************************************
132  *           DEBUG_IsBadWritePtr
133  *
134  * Check if we are allowed to write memory at 'address'.
135  */
136 BOOL DEBUG_IsBadWritePtr( const DBG_ADDR *address, int size )
137 {
138 #ifdef __i386__
139     if (!IS_SELECTOR_V86(address->seg))
140     if (address->seg)  /* segmented addr */
141     {
142         /* Note: we use IsBadReadPtr here because we are */
143         /* always allowed to write to read-only segments */
144         if (IsBadReadPtr16( (SEGPTR)MAKELONG( (WORD)address->off,
145                                               (WORD)address->seg ), size ))
146             return TRUE;
147     }
148 #endif
149     return DEBUG_checkmap_bad( DBG_ADDR_TO_LIN(address), size, 0);
150 }
151
152
153 /***********************************************************************
154  *           DEBUG_ReadMemory
155  *
156  * Read a memory value.
157  */
158 int DEBUG_ReadMemory( const DBG_ADDR *address )
159 {
160     DBG_ADDR addr = *address;
161
162     DBG_FIX_ADDR_SEG( &addr, DS_reg(&DEBUG_context) );
163     if (!DBG_CHECK_READ_PTR( &addr, sizeof(int) )) return 0;
164     return *(int *)DBG_ADDR_TO_LIN( &addr );
165 }
166
167
168 /***********************************************************************
169  *           DEBUG_WriteMemory
170  *
171  * Store a value in memory.
172  */
173 void DEBUG_WriteMemory( const DBG_ADDR *address, int value )
174 {
175     DBG_ADDR addr = *address;
176
177     DBG_FIX_ADDR_SEG( &addr, DS_reg(&DEBUG_context) );
178     if (!DBG_CHECK_WRITE_PTR( &addr, sizeof(int) )) return;
179     *(int *)DBG_ADDR_TO_LIN( &addr ) = value;
180 }
181
182
183 /***********************************************************************
184  *           DEBUG_ExamineMemory
185  *
186  * Implementation of the 'x' command.
187  */
188 void DEBUG_ExamineMemory( const DBG_ADDR *address, int count, char format )
189 {
190     DBG_ADDR addr =     * address;
191     unsigned int        * dump;
192     int                   i;
193     unsigned char       * pnt;
194     unsigned int          seg2;
195     struct datatype     * testtype;
196     unsigned short int  * wdump;
197
198     DBG_FIX_ADDR_SEG( &addr, (format == 'i') ?
199                              CS_reg(&DEBUG_context) : DS_reg(&DEBUG_context) );
200
201     /*
202      * Dereference pointer to get actual memory address we need to be
203      * reading.  We will use the same segment as what we have already,
204      * and hope that this is a sensible thing to do.
205      */
206     if( addr.type != NULL )
207       {
208         if( addr.type == DEBUG_TypeIntConst )
209           {
210             /*
211              * We know that we have the actual offset stored somewhere
212              * else in 32-bit space.  Grab it, and we
213              * should be all set.
214              */
215             seg2 = addr.seg;
216             addr.seg = 0;
217             addr.off = DEBUG_GetExprValue(&addr, NULL);
218             addr.seg = seg2;
219           }
220         else
221           {
222             if (!DBG_CHECK_READ_PTR( &addr, 1 )) return;
223             DEBUG_TypeDerefPointer(&addr, &testtype);
224             if( testtype != NULL || addr.type == DEBUG_TypeIntConst )
225               {
226                 addr.off = DEBUG_GetExprValue(&addr, NULL);
227               }
228           }
229       }
230     else if (!addr.seg && !addr.off)
231     {
232         fprintf(stderr,"Invalid expression\n");
233         return;
234     }
235
236     if (format != 'i' && count > 1)
237     {
238         DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
239         fprintf(stderr,": ");
240     }
241
242     pnt = DBG_ADDR_TO_LIN( &addr );
243
244     switch(format)
245     {
246         case 'u': {
247                 WCHAR *ptr = (WCHAR*)pnt;
248                 if (count == 1) count = 256;
249                 while (count--)
250                 {
251                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(WCHAR) )) return;
252                     if (!*ptr) break;
253                     addr.off++;
254                     fputc( (char)*ptr++, stderr );
255                 }
256                 fprintf(stderr,"\n");
257                 return;
258             }
259         case 's':
260                 if (count == 1) count = 256;
261                 while (count--)
262                 {
263                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(char) )) return;
264                     if (!*pnt) break;
265                     addr.off++;
266                     fputc( *pnt++, stderr );
267                 }
268                 fprintf(stderr,"\n");
269                 return;
270
271         case 'i':
272                 while (count--)
273                 {
274                     DEBUG_PrintAddress( &addr, dbg_mode, TRUE );
275                     fprintf(stderr,": ");
276                     if (!DBG_CHECK_READ_PTR( &addr, 1 )) return;
277                     DEBUG_Disasm( &addr, TRUE );
278                     fprintf(stderr,"\n");
279                 }
280                 return;
281         case 'x':
282                 dump = (unsigned int *)pnt;
283                 for(i=0; i<count; i++) 
284                 {
285                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(int) )) return;
286                     fprintf(stderr," %8.8x", *dump++);
287                     addr.off += sizeof(int);
288                     if ((i % 4) == 3)
289                     {
290                         fprintf(stderr,"\n");
291                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
292                         fprintf(stderr,": ");
293                     }
294                 }
295                 fprintf(stderr,"\n");
296                 return;
297         
298         case 'd':
299                 dump = (unsigned int *)pnt;
300                 for(i=0; i<count; i++) 
301                 {
302                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(int) )) return;
303                     fprintf(stderr," %10d", *dump++);
304                     addr.off += sizeof(int);
305                     if ((i % 4) == 3)
306                     {
307                         fprintf(stderr,"\n");
308                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
309                         fprintf(stderr,": ");
310                     }
311                 }
312                 fprintf(stderr,"\n");
313                 return;
314         
315         case 'w':
316                 wdump = (unsigned short *)pnt;
317                 for(i=0; i<count; i++) 
318                 {
319                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(short) )) return;
320                     fprintf(stderr," %04x", *wdump++);
321                     addr.off += sizeof(short);
322                     if ((i % 8) == 7)
323                     {
324                         fprintf(stderr,"\n");
325                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
326                         fprintf(stderr,": ");
327                     }
328                 }
329                 fprintf(stderr,"\n");
330                 return;
331         
332         case 'c':
333                 for(i=0; i<count; i++) 
334                 {
335                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(char) )) return;
336                     if(*pnt < 0x20)
337                     {
338                         fprintf(stderr,"  ");
339                         pnt++;
340                     }
341                     else fprintf(stderr," %c", *pnt++);
342                     addr.off++;
343                     if ((i % 32) == 31)
344                     {
345                         fprintf(stderr,"\n");
346                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
347                         fprintf(stderr,": ");
348                     }
349                 }
350                 fprintf(stderr,"\n");
351                 return;
352         
353         case 'b':
354                 for(i=0; i<count; i++) 
355                 {
356                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(char) )) return;
357                     fprintf(stderr," %02x", (*pnt++) & 0xff);
358                     addr.off++;
359                     if ((i % 16) == 15)
360                     {
361                         fprintf(stderr,"\n");
362                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
363                         fprintf(stderr,": ");
364                     }
365                 }
366                 fprintf(stderr,"\n");
367                 return;
368         }
369 }