| /* | 
 |  * Debugger memory handling | 
 |  * | 
 |  * Copyright 1993 Eric Youngdale | 
 |  * Copyright 1995 Alexandre Julliard | 
 |  */ | 
 |  | 
 | #include <stdio.h> | 
 | #include <stdlib.h> | 
 | #include "windows.h" | 
 | #include "debugger.h" | 
 |  | 
 |  | 
 | /************************************************************ | 
 |  *    | 
 |  *  Check if linear pointer in [addr, addr+size[ | 
 |  *     read  (rwflag == 1) | 
 |  *   or | 
 |  *     write (rwflag == 0) | 
 |  ************************************************************/ | 
 |  | 
 | #if defined(linux) || defined(__FreeBSD__) | 
 | BOOL32 DEBUG_checkmap_bad( const char *addr, size_t size, int rwflag) | 
 | { | 
 |   FILE *fp; | 
 |   char buf[80];      /* temporary line buffer */ | 
 |   char prot[5];      /* protection string */ | 
 |   char *start, *end; | 
 |   int ret = TRUE; | 
 |  | 
 | #ifdef linux | 
 |   /*  | 
 |      The entries in /proc/self/maps are of the form: | 
 |      08000000-08002000 r-xp 00000000 03:41 2361 | 
 |      08002000-08003000 rw-p 00001000 03:41 2361 | 
 |      08003000-08005000 rwxp 00000000 00:00 0 | 
 |      40000000-40005000 r-xp 00000000 03:41 67219 | 
 |      40005000-40006000 rw-p 00004000 03:41 67219 | 
 |      40006000-40007000 rw-p 00000000 00:00 0 | 
 |      ... | 
 |       start    end     perm   ???    major:minor inode | 
 |  | 
 |      Only permissions start and end are used here | 
 |      */ | 
 | #else | 
 | /* | 
 |     % cat /proc/curproc/map | 
 |     start      end         resident   private perm    type | 
 |     0x1000     0xe000            12         0 r-x COW vnode | 
 |     0xe000     0x10000            2         2 rwx COW vnode | 
 |     0x10000    0x27000            4         4 rwx     default | 
 |     0x800e000  0x800f000          1         1 rw-     default | 
 |     0xefbde000 0xefbfe000         1         1 rwx     default | 
 |      | 
 |     COW = "copy on write" | 
 | */ | 
 | #endif | 
 |  | 
 |    | 
 | #ifdef linux | 
 |   if (!(fp = fopen("/proc/self/maps", "r"))) | 
 | #else | 
 |   if (!(fp = fopen("/proc/curproc/map", "r"))) | 
 | #endif | 
 |     return FALSE;  | 
 |  | 
 |   while (fgets( buf, 79, fp)) { | 
 | #ifdef linux | 
 |     sscanf(buf, "%x-%x %3s", (int *) &start, (int *) &end, prot); | 
 | #else | 
 |     sscanf(buf, "%x %x %*d %*d %3s", (int *) &start, (int *) &end, prot); | 
 | #endif | 
 |     if ( end <= addr) | 
 |       continue; | 
 |     if (start <= addr && addr+size < end) { | 
 |       if (rwflag)  | 
 | 	ret = (prot[0] != 'r'); /* test for reading */ | 
 |       else | 
 | 	ret = (prot[1] != 'w'); /* test for writing */ | 
 |     } | 
 |     break; | 
 |   } | 
 |   fclose( fp); | 
 |   return ret; | 
 | } | 
 | #else  /* linux || FreeBSD */ | 
 | /* FIXME: code needed for BSD et al. */ | 
 | BOOL32 DEBUG_checkmap_bad(char *addr, size_t size, int rwflag) | 
 | { | 
 |     return FALSE; | 
 | } | 
 | #endif  /* linux || FreeBSD */ | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           DEBUG_IsBadReadPtr | 
 |  * | 
 |  * Check if we are allowed to read memory at 'address'. | 
 |  */ | 
 | BOOL32 DEBUG_IsBadReadPtr( const DBG_ADDR *address, int size ) | 
 | { | 
 |     if (!IS_SELECTOR_V86(address->seg)) | 
 |     if (address->seg)  /* segmented addr */ | 
 |     { | 
 |         if (IsBadReadPtr16( (SEGPTR)MAKELONG( (WORD)address->off, | 
 |                                               (WORD)address->seg ), size )) | 
 |             return TRUE; | 
 |     } | 
 |     return DEBUG_checkmap_bad( DBG_ADDR_TO_LIN(address), size, 1); | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           DEBUG_IsBadWritePtr | 
 |  * | 
 |  * Check if we are allowed to write memory at 'address'. | 
 |  */ | 
 | BOOL32 DEBUG_IsBadWritePtr( const DBG_ADDR *address, int size ) | 
 | { | 
 |     if (!IS_SELECTOR_V86(address->seg)) | 
 |     if (address->seg)  /* segmented addr */ | 
 |     { | 
 |         /* Note: we use IsBadReadPtr here because we are */ | 
 |         /* always allowed to write to read-only segments */ | 
 |         if (IsBadReadPtr16( (SEGPTR)MAKELONG( (WORD)address->off, | 
 |                                               (WORD)address->seg ), size )) | 
 |             return TRUE; | 
 |     } | 
 |     return DEBUG_checkmap_bad( DBG_ADDR_TO_LIN(address), size, 0); | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           DEBUG_ReadMemory | 
 |  * | 
 |  * Read a memory value. | 
 |  */ | 
 | int DEBUG_ReadMemory( const DBG_ADDR *address ) | 
 | { | 
 |     DBG_ADDR addr = *address; | 
 |  | 
 |     DBG_FIX_ADDR_SEG( &addr, DS_reg(&DEBUG_context) ); | 
 |     if (!DBG_CHECK_READ_PTR( &addr, sizeof(int) )) return 0; | 
 |     return *(int *)DBG_ADDR_TO_LIN( &addr ); | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           DEBUG_WriteMemory | 
 |  * | 
 |  * Store a value in memory. | 
 |  */ | 
 | void DEBUG_WriteMemory( const DBG_ADDR *address, int value ) | 
 | { | 
 |     DBG_ADDR addr = *address; | 
 |  | 
 |     DBG_FIX_ADDR_SEG( &addr, DS_reg(&DEBUG_context) ); | 
 |     if (!DBG_CHECK_WRITE_PTR( &addr, sizeof(int) )) return; | 
 |     *(int *)DBG_ADDR_TO_LIN( &addr ) = value; | 
 | } | 
 |  | 
 |  | 
 | /*********************************************************************** | 
 |  *           DEBUG_ExamineMemory | 
 |  * | 
 |  * Implementation of the 'x' command. | 
 |  */ | 
 | void DEBUG_ExamineMemory( const DBG_ADDR *address, int count, char format ) | 
 | { | 
 |     DBG_ADDR addr =	* address; | 
 |     unsigned int	* dump; | 
 |     int			  i; | 
 |     unsigned char	* pnt; | 
 |     unsigned int	  seg2; | 
 |     struct datatype	* testtype; | 
 |     unsigned short int	* wdump; | 
 |  | 
 |     DBG_FIX_ADDR_SEG( &addr, (format == 'i') ? | 
 |                              CS_reg(&DEBUG_context) : DS_reg(&DEBUG_context) ); | 
 |  | 
 |     /* | 
 |      * Dereference pointer to get actual memory address we need to be | 
 |      * reading.  We will use the same segment as what we have already, | 
 |      * and hope that this is a sensible thing to do. | 
 |      */ | 
 |     if( addr.type != NULL ) | 
 |       { | 
 | 	if( addr.type == DEBUG_TypeIntConst ) | 
 | 	  { | 
 | 	    /* | 
 | 	     * We know that we have the actual offset stored somewhere | 
 | 	     * else in 32-bit space.  Grab it, and we | 
 | 	     * should be all set. | 
 | 	     */ | 
 | 	    seg2 = addr.seg; | 
 | 	    addr.seg = 0; | 
 | 	    addr.off = DEBUG_GetExprValue(&addr, NULL); | 
 | 	    addr.seg = seg2; | 
 | 	  } | 
 | 	else | 
 | 	  { | 
 | 	    if (!DBG_CHECK_READ_PTR( &addr, 1 )) return; | 
 | 	    DEBUG_TypeDerefPointer(&addr, &testtype); | 
 | 	    if( testtype != NULL || addr.type == DEBUG_TypeIntConst ) | 
 | 	      { | 
 | 		addr.off = DEBUG_GetExprValue(&addr, NULL); | 
 | 	      } | 
 | 	  } | 
 |       } | 
 |     else if (!addr.seg && !addr.off) | 
 |     { | 
 | 	fprintf(stderr,"Invalid expression\n"); | 
 | 	return; | 
 |     } | 
 |  | 
 |     if (format != 'i' && count > 1) | 
 |     { | 
 |         DEBUG_PrintAddress( &addr, dbg_mode, FALSE ); | 
 |         fprintf(stderr,": "); | 
 |     } | 
 |  | 
 |     pnt = DBG_ADDR_TO_LIN( &addr ); | 
 |  | 
 |     switch(format) | 
 |     { | 
 | 	case 'u': { | 
 | 		WCHAR *ptr = (WCHAR*)pnt; | 
 | 		if (count == 1) count = 256; | 
 |                 while (count--) | 
 |                 { | 
 |                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(WCHAR) )) return; | 
 |                     if (!*ptr) break; | 
 |                     addr.off++; | 
 |                     fputc( (char)*ptr++, stderr ); | 
 |                 } | 
 | 		fprintf(stderr,"\n"); | 
 | 		return; | 
 | 	    } | 
 | 	case 's': | 
 | 		if (count == 1) count = 256; | 
 |                 while (count--) | 
 |                 { | 
 |                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(char) )) return; | 
 |                     if (!*pnt) break; | 
 |                     addr.off++; | 
 |                     fputc( *pnt++, stderr ); | 
 |                 } | 
 | 		fprintf(stderr,"\n"); | 
 | 		return; | 
 |  | 
 | 	case 'i': | 
 | 		while (count--) | 
 |                 { | 
 |                     DEBUG_PrintAddress( &addr, dbg_mode, TRUE ); | 
 |                     fprintf(stderr,": "); | 
 |                     if (!DBG_CHECK_READ_PTR( &addr, 1 )) return; | 
 |                     DEBUG_Disasm( &addr, TRUE ); | 
 |                     fprintf(stderr,"\n"); | 
 | 		} | 
 | 		return; | 
 | 	case 'x': | 
 | 		dump = (unsigned int *)pnt; | 
 | 		for(i=0; i<count; i++)  | 
 | 		{ | 
 |                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(int) )) return; | 
 |                     fprintf(stderr," %8.8x", *dump++); | 
 |                     addr.off += sizeof(int); | 
 |                     if ((i % 8) == 7) | 
 |                     { | 
 |                         fprintf(stderr,"\n"); | 
 |                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE ); | 
 |                         fprintf(stderr,": "); | 
 |                     } | 
 | 		} | 
 | 		fprintf(stderr,"\n"); | 
 | 		return; | 
 | 	 | 
 | 	case 'd': | 
 | 		dump = (unsigned int *)pnt; | 
 | 		for(i=0; i<count; i++)  | 
 | 		{ | 
 |                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(int) )) return; | 
 |                     fprintf(stderr," %d", *dump++); | 
 |                     addr.off += sizeof(int); | 
 |                     if ((i % 8) == 7) | 
 |                     { | 
 |                         fprintf(stderr,"\n"); | 
 |                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE ); | 
 |                         fprintf(stderr,": "); | 
 |                     } | 
 | 		} | 
 | 		fprintf(stderr,"\n"); | 
 | 		return; | 
 | 	 | 
 | 	case 'w': | 
 | 		wdump = (unsigned short *)pnt; | 
 | 		for(i=0; i<count; i++)  | 
 | 		{ | 
 |                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(short) )) return; | 
 |                     fprintf(stderr," %04x", *wdump++); | 
 |                     addr.off += sizeof(short); | 
 |                     if ((i % 8) == 7) | 
 |                     { | 
 |                         fprintf(stderr,"\n"); | 
 |                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE ); | 
 |                         fprintf(stderr,": "); | 
 |                     } | 
 | 		} | 
 | 		fprintf(stderr,"\n"); | 
 | 		return; | 
 | 	 | 
 | 	case 'c': | 
 | 		for(i=0; i<count; i++)  | 
 | 		{ | 
 |                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(char) )) return; | 
 |                     if(*pnt < 0x20) | 
 |                     { | 
 |                         fprintf(stderr,"  "); | 
 |                         pnt++; | 
 |                     } | 
 |                     else fprintf(stderr," %c", *pnt++); | 
 |                     addr.off++; | 
 |                     if ((i % 32) == 31) | 
 |                     { | 
 |                         fprintf(stderr,"\n"); | 
 |                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE ); | 
 |                         fprintf(stderr,": "); | 
 |                     } | 
 | 		} | 
 | 		fprintf(stderr,"\n"); | 
 | 		return; | 
 | 	 | 
 | 	case 'b': | 
 | 		for(i=0; i<count; i++)  | 
 | 		{ | 
 |                     if (!DBG_CHECK_READ_PTR( &addr, sizeof(char) )) return; | 
 |                     fprintf(stderr," %02x", (*pnt++) & 0xff); | 
 |                     addr.off++; | 
 |                     if ((i % 16) == 15) | 
 |                     { | 
 |                         fprintf(stderr,"\n"); | 
 |                         DEBUG_PrintAddress( &addr, dbg_mode, FALSE ); | 
 |                         fprintf(stderr,": "); | 
 |                     } | 
 | 		} | 
 | 		fprintf(stderr,"\n"); | 
 | 		return; | 
 | 	} | 
 | } |