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