Check when backtracking the stack if frames are correct (readable).
[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   while (fgets( buf, sizeof(buf)-1, fp)) {
77 #ifdef linux
78     sscanf(buf, "%x-%x %3s", (int *) &start, (int *) &end, prot);
79 #else
80     sscanf(buf, "%x %x %*d %*d %3s", (int *) &start, (int *) &end, prot);
81     if (prot[0]!='r' && prot[0]!='-') /* FreeBSD 3.0 format */
82        sscanf(buf, "%x %x %*d %*d %*d %3s", (int *) &start, (int *) &end, prot);
83 #endif
84     if ( end <= addr)
85       continue;
86     if (start <= addr && addr+size <= end) {
87       if (rwflag) 
88         ret = (prot[0] != 'r'); /* test for reading */
89       else
90         ret = (prot[1] != 'w'); /* test for writing */
91     }
92     break;
93   }
94   fclose( fp);
95   return ret;
96 }
97
98
99 /***********************************************************************
100  *           DEBUG_IsBadReadPtr
101  *
102  * Check if we are allowed to read memory at 'address'.
103  */
104 BOOL DEBUG_IsBadReadPtr( const DBG_ADDR *address, int size )
105 {
106     if (!IS_SELECTOR_V86(address->seg))
107     if (address->seg)  /* segmented addr */
108     {
109         if (IsBadReadPtr16( (SEGPTR)MAKELONG( (WORD)address->off,
110                                               (WORD)address->seg ), size ))
111             return TRUE;
112     }
113     return DEBUG_checkmap_bad( DBG_ADDR_TO_LIN(address), size, 1);
114 }
115
116
117 /***********************************************************************
118  *           DEBUG_IsBadWritePtr
119  *
120  * Check if we are allowed to write memory at 'address'.
121  */
122 BOOL DEBUG_IsBadWritePtr( const DBG_ADDR *address, int size )
123 {
124     if (!IS_SELECTOR_V86(address->seg))
125     if (address->seg)  /* segmented addr */
126     {
127         /* Note: we use IsBadReadPtr here because we are */
128         /* always allowed to write to read-only segments */
129         if (IsBadReadPtr16( (SEGPTR)MAKELONG( (WORD)address->off,
130                                               (WORD)address->seg ), size ))
131             return TRUE;
132     }
133     return DEBUG_checkmap_bad( DBG_ADDR_TO_LIN(address), size, 0);
134 }
135
136
137 /***********************************************************************
138  *           DEBUG_ReadMemory
139  *
140  * Read a memory value.
141  */
142 int DEBUG_ReadMemory( const DBG_ADDR *address )
143 {
144     DBG_ADDR addr = *address;
145
146     DBG_FIX_ADDR_SEG( &addr, DS_reg(&DEBUG_context) );
147     if (!DBG_CHECK_READ_PTR( &addr, sizeof(int) )) return 0;
148     return *(int *)DBG_ADDR_TO_LIN( &addr );
149 }
150
151
152 /***********************************************************************
153  *           DEBUG_WriteMemory
154  *
155  * Store a value in memory.
156  */
157 void DEBUG_WriteMemory( const DBG_ADDR *address, int value )
158 {
159     DBG_ADDR addr = *address;
160
161     DBG_FIX_ADDR_SEG( &addr, DS_reg(&DEBUG_context) );
162     if (!DBG_CHECK_WRITE_PTR( &addr, sizeof(int) )) return;
163     *(int *)DBG_ADDR_TO_LIN( &addr ) = value;
164 }
165
166
167 /***********************************************************************
168  *           DEBUG_ExamineMemory
169  *
170  * Implementation of the 'x' command.
171  */
172 void DEBUG_ExamineMemory( const DBG_ADDR *address, int count, char format )
173 {
174     DBG_ADDR addr =     * address;
175     unsigned int        * dump;
176     int                   i;
177     unsigned char       * pnt;
178     unsigned int          seg2;
179     struct datatype     * testtype;
180     unsigned short int  * wdump;
181
182     DBG_FIX_ADDR_SEG( &addr, (format == 'i') ?
183                              CS_reg(&DEBUG_context) : DS_reg(&DEBUG_context) );
184
185     /*
186      * Dereference pointer to get actual memory address we need to be
187      * reading.  We will use the same segment as what we have already,
188      * and hope that this is a sensible thing to do.
189      */
190     if( addr.type != NULL )
191       {
192         if( addr.type == DEBUG_TypeIntConst )
193           {
194             /*
195              * We know that we have the actual offset stored somewhere
196              * else in 32-bit space.  Grab it, and we
197              * should be all set.
198              */
199             seg2 = addr.seg;
200             addr.seg = 0;
201             addr.off = DEBUG_GetExprValue(&addr, NULL);
202             addr.seg = seg2;
203           }
204         else
205           {
206             if (!DBG_CHECK_READ_PTR( &addr, 1 )) return;
207             DEBUG_TypeDerefPointer(&addr, &testtype);
208             if( testtype != NULL || addr.type == DEBUG_TypeIntConst )
209               {
210                 addr.off = DEBUG_GetExprValue(&addr, NULL);
211               }
212           }
213       }
214     else if (!addr.seg && !addr.off)
215     {
216         fprintf(stderr,"Invalid expression\n");
217         return;
218     }
219
220     if (format != 'i' && count > 1)
221     {
222         DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
223         fprintf(stderr,": ");
224     }
225
226     pnt = DBG_ADDR_TO_LIN( &addr );
227
228     switch(format)
229     {
230         case 'u': {
231                 WCHAR *ptr = (WCHAR*)pnt;
232                 if (count == 1) count = 256;
233                 while (count--)
234                 {
235                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(WCHAR) )) return;
236                     if (!*ptr) break;
237                     addr.off++;
238                     fputc( (char)*ptr++, stderr );
239                 }
240                 fprintf(stderr,"\n");
241                 return;
242             }
243         case 's':
244                 if (count == 1) count = 256;
245                 while (count--)
246                 {
247                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(char) )) return;
248                     if (!*pnt) break;
249                     addr.off++;
250                     fputc( *pnt++, stderr );
251                 }
252                 fprintf(stderr,"\n");
253                 return;
254
255         case 'i':
256                 while (count--)
257                 {
258                     DEBUG_PrintAddress( &addr, dbg_mode, TRUE );
259                     fprintf(stderr,": ");
260                     if (!DBG_CHECK_READ_PTR( &addr, 1 )) return;
261                     DEBUG_Disasm( &addr, TRUE );
262                     fprintf(stderr,"\n");
263                 }
264                 return;
265         case 'x':
266                 dump = (unsigned int *)pnt;
267                 for(i=0; i<count; i++) 
268                 {
269                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(int) )) return;
270                     fprintf(stderr," %8.8x", *dump++);
271                     addr.off += sizeof(int);
272                     if ((i % 4) == 3)
273                     {
274                         fprintf(stderr,"\n");
275                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
276                         fprintf(stderr,": ");
277                     }
278                 }
279                 fprintf(stderr,"\n");
280                 return;
281         
282         case 'd':
283                 dump = (unsigned int *)pnt;
284                 for(i=0; i<count; i++) 
285                 {
286                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(int) )) return;
287                     fprintf(stderr," %10d", *dump++);
288                     addr.off += sizeof(int);
289                     if ((i % 4) == 3)
290                     {
291                         fprintf(stderr,"\n");
292                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
293                         fprintf(stderr,": ");
294                     }
295                 }
296                 fprintf(stderr,"\n");
297                 return;
298         
299         case 'w':
300                 wdump = (unsigned short *)pnt;
301                 for(i=0; i<count; i++) 
302                 {
303                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(short) )) return;
304                     fprintf(stderr," %04x", *wdump++);
305                     addr.off += sizeof(short);
306                     if ((i % 8) == 7)
307                     {
308                         fprintf(stderr,"\n");
309                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
310                         fprintf(stderr,": ");
311                     }
312                 }
313                 fprintf(stderr,"\n");
314                 return;
315         
316         case 'c':
317                 for(i=0; i<count; i++) 
318                 {
319                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(char) )) return;
320                     if(*pnt < 0x20)
321                     {
322                         fprintf(stderr,"  ");
323                         pnt++;
324                     }
325                     else fprintf(stderr," %c", *pnt++);
326                     addr.off++;
327                     if ((i % 32) == 31)
328                     {
329                         fprintf(stderr,"\n");
330                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE );
331                         fprintf(stderr,": ");
332                     }
333                 }
334                 fprintf(stderr,"\n");
335                 return;
336         
337         case 'b':
338                 for(i=0; i<count; i++) 
339                 {
340                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(char) )) return;
341                     fprintf(stderr," %02x", (*pnt++) & 0xff);
342                     addr.off++;
343                     if ((i % 16) == 15)
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 }