]> rtime.felk.cvut.cz Git - l4.git/blobdiff - l4/pkg/valgrind/src/valgrind-3.6.0-svn/memcheck/mc_main.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / memcheck / mc_main.c
index 0dee75c063c709f65990036ab811bd3cc7f6f1d4..de6f84414d397e941325d4e9cebbe96924330f3b 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "pub_tool_basics.h"
 #include "pub_tool_aspacemgr.h"
+#include "pub_tool_gdbserver.h"
 #include "pub_tool_hashtable.h"     // For mc_include.h
 #include "pub_tool_libcbase.h"
 #include "pub_tool_libcassert.h"
@@ -1052,67 +1053,17 @@ INLINE Bool MC_(in_ignored_range) ( Addr a )
    return False;
 }
 
-
-/* Parse a 32- or 64-bit hex number, including leading 0x, from string
-   starting at *ppc, putting result in *result, and return True.  Or
-   fail, in which case *ppc and *result are undefined, and return
-   False. */
-
-static Bool isHex ( UChar c )
-{
-  return ((c >= '0' && c <= '9') ||
-         (c >= 'a' && c <= 'f') ||
-         (c >= 'A' && c <= 'F'));
-}
-
-static UInt fromHex ( UChar c )
-{
-   if (c >= '0' && c <= '9')
-      return (UInt)c - (UInt)'0';
-   if (c >= 'a' && c <= 'f')
-      return 10 +  (UInt)c - (UInt)'a';
-   if (c >= 'A' && c <= 'F')
-      return 10 +  (UInt)c - (UInt)'A';
-   /*NOTREACHED*/
-   tl_assert(0);
-   return 0;
-}
-
-static Bool parse_Addr ( UChar** ppc, Addr* result )
-{
-   Int used, limit = 2 * sizeof(Addr);
-   if (**ppc != '0')
-      return False;
-   (*ppc)++;
-   if (**ppc != 'x')
-      return False;
-   (*ppc)++;
-   *result = 0;
-   used = 0;
-   while (isHex(**ppc)) {
-      UInt d = fromHex(**ppc);
-      tl_assert(d < 16);
-      *result = ((*result) << 4) | fromHex(**ppc);
-      (*ppc)++;
-      used++;
-      if (used > limit) return False;
-   }
-   if (used == 0)
-      return False;
-   return True;
-}
-
-/* Parse two such numbers separated by a dash, or fail. */
+/* Parse two Addr separated by a dash, or fail. */
 
 static Bool parse_range ( UChar** ppc, Addr* result1, Addr* result2 )
 {
-   Bool ok = parse_Addr(ppc, result1);
+   Bool ok = VG_(parse_Addr) (ppc, result1);
    if (!ok)
       return False;
    if (**ppc != '-')
       return False;
    (*ppc)++;
-   ok = parse_Addr(ppc, result2);
+   ok = VG_(parse_Addr) (ppc, result2);
    if (!ok)
       return False;
    return True;
@@ -3867,7 +3818,7 @@ static UInt mb_get_origin_for_guest_offset ( ThreadId tid,
 static void mc_post_reg_write ( CorePart part, ThreadId tid, 
                                 PtrdiffT offset, SizeT size)
 {
-#  define MAX_REG_WRITE_SIZE 1408
+#  define MAX_REG_WRITE_SIZE 1664
    UChar area[MAX_REG_WRITE_SIZE];
    tl_assert(size <= MAX_REG_WRITE_SIZE);
    VG_(memset)(area, V_BITS8_DEFINED, size);
@@ -4516,17 +4467,20 @@ static Int mc_get_or_set_vbits_for_client (
    Addr a, 
    Addr vbits, 
    SizeT szB, 
-   Bool setting /* True <=> set vbits,  False <=> get vbits */ 
+   Bool setting, /* True <=> set vbits,  False <=> get vbits */ 
+   Bool is_client_request /* True <=> real user request 
+                             False <=> internal call from gdbserver */ 
 )
 {
    SizeT i;
    Bool  ok;
    UChar vbits8;
 
-   /* Check that arrays are addressible before doing any getting/setting. */
+   /* Check that arrays are addressible before doing any getting/setting.
+      vbits to be checked only for real user request. */
    for (i = 0; i < szB; i++) {
       if (VA_BITS2_NOACCESS == get_vabits2(a + i) ||
-          VA_BITS2_NOACCESS == get_vabits2(vbits + i)) {
+          (is_client_request && VA_BITS2_NOACCESS == get_vabits2(vbits + i))) {
          return 3;
       }
    }
@@ -4545,8 +4499,9 @@ static Int mc_get_or_set_vbits_for_client (
          tl_assert(ok);
          ((UChar*)vbits)[i] = vbits8;
       }
-      // The bytes in vbits[] have now been set, so mark them as such.
-      MC_(make_mem_defined)(vbits, szB);
+      if (is_client_request)
+        // The bytes in vbits[] have now been set, so mark them as such.
+        MC_(make_mem_defined)(vbits, szB);
    }
 
    return 1;
@@ -4743,7 +4698,7 @@ static Bool mc_expensive_sanity_check ( void )
 /*------------------------------------------------------------*/
 
 Bool          MC_(clo_partial_loads_ok)       = False;
-Long          MC_(clo_freelist_vol)           = 10*1000*1000LL;
+Long          MC_(clo_freelist_vol)           = 20*1000*1000LL;
 LeakCheckMode MC_(clo_leak_check)             = LC_Summary;
 VgRes         MC_(clo_leak_resolution)        = Vg_HighRes;
 Bool          MC_(clo_show_reachable)         = False;
@@ -4874,7 +4829,7 @@ static void mc_print_usage(void)
 "    --undef-value-errors=no|yes      check for undefined value errors [yes]\n"
 "    --track-origins=no|yes           show origins of undefined values? [no]\n"
 "    --partial-loads-ok=no|yes        too hard to explain here; see manual [no]\n"
-"    --freelist-vol=<number>          volume of freed blocks queue [10000000]\n"
+"    --freelist-vol=<number>          volume of freed blocks queue [20000000]\n"
 "    --workaround-gcc296-bugs=no|yes  self explanatory [no]\n"
 "    --ignore-ranges=0xPP-0xQQ[,0xRR-0xSS]   assume given addresses are OK\n"
 "    --malloc-fill=<hexnumber>        fill malloc'd areas with given value\n"
@@ -4977,6 +4932,220 @@ static void show_client_block_stats ( void )
    );
 }
 
+static void print_monitor_help ( void )
+{
+   VG_(gdb_printf) 
+      (
+"\n"
+"memcheck monitor commands:\n"
+"  mc.get_vbits <addr> [<len>]\n"
+"        returns validity bits for <len> (or 1) bytes at <addr>\n"
+"            bit values 0 = valid, 1 = invalid, __ = unaddressable byte\n"
+"        Example: mc.get_vbits 0x8049c78 10\n"
+"  mc.make_memory [noaccess|undefined\n"
+"                     |defined|ifaddressabledefined] <addr> [<len>]\n"
+"        mark <len> (or 1) bytes at <addr> with the given accessibility\n"
+"  mc.check_memory [addressable|defined] <addr> [<len>]\n"
+"        check that <len> (or 1) bytes at <addr> have the given accessibility\n"
+"            and outputs a description of <addr>\n"
+"  mc.leak_check [full*|summary]\n"
+"                [reachable|leakpossible*|definiteleak]\n"
+"            * = defaults\n"
+"        Examples: mc.leak_check\n"
+"                  mc.leak_check any summary\n"
+"\n");
+}
+
+/* return True if request recognised, False otherwise */
+static Bool handle_gdb_monitor_command (ThreadId tid, Char *req)
+{
+   Char* wcmd;
+   Char s[VG_(strlen(req))]; /* copy for strtok_r */
+   Char *ssaveptr;
+
+   VG_(strcpy) (s, req);
+
+   wcmd = VG_(strtok_r) (s, " ", &ssaveptr);
+   /* NB: if possible, avoid introducing a new command below which
+      starts with the same 4 first letters as an already existing
+      command. This ensures a shorter abbreviation for the user. */
+   switch (VG_(keyword_id) 
+           ("help mc.get_vbits mc.leak_check mc.make_memory mc.check_memory", 
+            wcmd, kwd_report_duplicated_matches)) {
+   case -2: /* multiple matches */
+      return True;
+   case -1: /* not found */
+      return False;
+   case  0: /* help */
+      print_monitor_help();
+      return True;
+   case  1: { /* mc.get_vbits */
+      Addr address;
+      SizeT szB = 1;
+      VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr);
+      if (szB != 0) {
+         UChar vbits;
+         Int i;
+         Int unaddressable = 0;
+         for (i = 0; i < szB; i++) {
+            Int res = mc_get_or_set_vbits_for_client 
+               (address+i, (Addr) &vbits, 1, 
+                False, /* get them */
+                False  /* is client request */ ); 
+            if ((i % 32) == 0 && i != 0)
+               VG_(gdb_printf) ("\n");
+            else if ((i % 4) == 0 && i != 0)
+               VG_(gdb_printf) (" ");
+            if (res == 1) {
+               VG_(gdb_printf) ("%02x", vbits);
+            } else {
+               tl_assert(3 == res);
+               unaddressable++;
+               VG_(gdb_printf) ("__");
+            }
+         }
+         if ((i % 80) != 0)
+            VG_(gdb_printf) ("\n");
+         if (unaddressable) {
+            VG_(gdb_printf)
+               ("Address %p len %ld has %d bytes unaddressable\n",
+                (void *)address, szB, unaddressable);
+         }
+      }
+      return True;
+   }
+   case  2: { /* mc.leak_check */
+      Int err = 0;
+      Bool save_clo_show_reachable = MC_(clo_show_reachable);
+      Bool save_clo_show_possibly_lost = MC_(clo_show_possibly_lost);
+      Char* kw;
+
+      LeakCheckMode mode;
+      
+      MC_(clo_show_reachable) = False;
+      mode = LC_Full;
+      
+      for (kw = VG_(strtok_r) (NULL, " ", &ssaveptr); 
+           kw != NULL; 
+           kw = VG_(strtok_r) (NULL, " ", &ssaveptr)) {
+         switch (VG_(keyword_id) 
+                 ("full summary "
+                  "reachable leakpossible definiteleak",
+                  kw, kwd_report_all)) {
+         case -2: err++; break;
+         case -1: err++; break;
+         case  0: mode = LC_Full; break;
+         case  1: mode = LC_Summary; break;
+         case  2: MC_(clo_show_reachable) = True; 
+                  MC_(clo_show_possibly_lost) = True; break;
+         case  3: MC_(clo_show_reachable) = False;
+                  MC_(clo_show_possibly_lost) = True; break;
+         case  4: MC_(clo_show_reachable) = False;
+                  MC_(clo_show_possibly_lost) = False; break;
+         default: tl_assert (0);
+         }
+      }
+      if (!err)
+         MC_(detect_memory_leaks)(tid, mode);
+      
+      MC_(clo_show_reachable) = save_clo_show_reachable;
+      MC_(clo_show_possibly_lost) = save_clo_show_possibly_lost;
+      return True;
+   }
+      
+   case  3: { /* mc.make_memory */
+      Addr address;
+      SizeT szB = 1;
+      int kwdid = VG_(keyword_id) 
+         ("noaccess undefined defined ifaddressabledefined",
+          VG_(strtok_r) (NULL, " ", &ssaveptr), kwd_report_all);
+      VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr);
+      if (address == (Addr) 0 && szB == 0) return True;
+      switch (kwdid) {
+      case -2: break;
+      case -1: break;
+      case  0: MC_(make_mem_noaccess) (address, szB); break;
+      case  1: make_mem_undefined_w_tid_and_okind ( address, szB, tid, 
+                                                    MC_OKIND_USER ); break;
+      case  2: MC_(make_mem_defined) ( address, szB ); break;
+      case  3: make_mem_defined_if_addressable ( address, szB ); break;;
+      default: tl_assert(0);
+      }
+      return True;
+   }
+
+   case  4: { /* mc.check_memory */
+      Addr address;
+      SizeT szB = 1;
+      Addr bad_addr;
+      UInt okind;
+      char* src;
+      UInt otag;
+      UInt ecu;
+      ExeContext* origin_ec;
+      MC_ReadResult res;
+
+      int kwdid = VG_(keyword_id) 
+         ("addressable defined",
+          VG_(strtok_r) (NULL, " ", &ssaveptr), kwd_report_all);
+      VG_(strtok_get_address_and_size) (&address, &szB, &ssaveptr);
+      if (address == (Addr) 0 && szB == 0) return True;
+      switch (kwdid) {
+      case -2: break;
+      case -1: break;
+      case  0: 
+         if (is_mem_addressable ( address, szB, &bad_addr ))
+            VG_(gdb_printf) ("Address %p len %ld addressable\n", 
+                             (void *)address, szB);
+         else
+            VG_(gdb_printf)
+               ("Address %p len %ld not addressable:\nbad address %p\n",
+                (void *)address, szB, (void *) bad_addr);
+         MC_(pp_describe_addr) (address);
+         break;
+      case  1: res = is_mem_defined ( address, szB, &bad_addr, &otag );
+         if (MC_AddrErr == res)
+            VG_(gdb_printf)
+               ("Address %p len %ld not addressable:\nbad address %p\n",
+                (void *)address, szB, (void *) bad_addr);
+         else if (MC_ValueErr == res) {
+            okind = otag & 3;
+            switch (okind) {
+            case MC_OKIND_STACK:   
+               src = " was created by a stack allocation"; break;
+            case MC_OKIND_HEAP:    
+               src = " was created by a heap allocation"; break;
+            case MC_OKIND_USER:    
+               src = " was created by a client request"; break;
+            case MC_OKIND_UNKNOWN: 
+               src = ""; break;
+            default: tl_assert(0);
+            }
+            VG_(gdb_printf) 
+               ("Address %p len %ld not defined:\n"
+                "Uninitialised value at %p%s\n",
+                (void *)address, szB, (void *) bad_addr, src);
+            ecu = otag & ~3;
+            if (VG_(is_plausible_ECU)(ecu)) {
+               origin_ec = VG_(get_ExeContext_from_ECU)( ecu );
+               VG_(pp_ExeContext)( origin_ec );
+            }
+         }
+         else
+            VG_(gdb_printf) ("Address %p len %ld defined\n",
+                             (void *)address, szB);
+         MC_(pp_describe_addr) (address);
+         break;
+      default: tl_assert(0);
+      }
+      return True;
+   }
+
+   default: 
+      tl_assert(0);
+      return False;
+   }
+}
 
 /*------------------------------------------------------------*/
 /*--- Client requests                                      ---*/
@@ -4990,6 +5159,7 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
 
    if (!VG_IS_TOOL_USERREQ('M','C',arg[0])
        && VG_USERREQ__MALLOCLIKE_BLOCK != arg[0]
+       && VG_USERREQ__RESIZEINPLACE_BLOCK != arg[0]
        && VG_USERREQ__FREELIKE_BLOCK   != arg[0]
        && VG_USERREQ__CREATE_MEMPOOL   != arg[0]
        && VG_USERREQ__DESTROY_MEMPOOL  != arg[0]
@@ -4998,7 +5168,8 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
        && VG_USERREQ__MEMPOOL_TRIM     != arg[0]
        && VG_USERREQ__MOVE_MEMPOOL     != arg[0]
        && VG_USERREQ__MEMPOOL_CHANGE   != arg[0]
-       && VG_USERREQ__MEMPOOL_EXISTS   != arg[0])
+       && VG_USERREQ__MEMPOOL_EXISTS   != arg[0]
+       && VG_USERREQ__GDB_MONITOR_COMMAND   != arg[0])
       return False;
 
    switch (arg[0]) {
@@ -5076,12 +5247,16 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
 
       case VG_USERREQ__GET_VBITS:
          *ret = mc_get_or_set_vbits_for_client
-                   ( arg[1], arg[2], arg[3], False /* get them */ );
+                   ( arg[1], arg[2], arg[3],
+                     False /* get them */, 
+                     True /* is client request */ );
          break;
 
       case VG_USERREQ__SET_VBITS:
          *ret = mc_get_or_set_vbits_for_client
-                   ( arg[1], arg[2], arg[3], True /* set them */ );
+                   ( arg[1], arg[2], arg[3],
+                     True /* set them */,
+                     True /* is client request */ );
          break;
 
       case VG_USERREQ__COUNT_LEAKS: { /* count leaked bytes */
@@ -5124,6 +5299,15 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
                           MC_AllocCustom, MC_(malloc_list) );
          return True;
       }
+      case VG_USERREQ__RESIZEINPLACE_BLOCK: {
+         Addr p         = (Addr)arg[1];
+         SizeT oldSizeB =       arg[2];
+         SizeT newSizeB =       arg[3];
+         UInt rzB       =       arg[4];
+
+         MC_(handle_resizeInPlace) ( tid, p, oldSizeB, newSizeB, rzB );
+         return True;
+      }
       case VG_USERREQ__FREELIKE_BLOCK: {
          Addr p         = (Addr)arg[1];
          UInt rzB       =       arg[2];
@@ -5208,6 +5392,14 @@ static Bool mc_handle_client_request ( ThreadId tid, UWord* arg, UWord* ret )
         return True;
       }
 
+      case VG_USERREQ__GDB_MONITOR_COMMAND: {
+         Bool handled = handle_gdb_monitor_command (tid, (Char*)arg[1]);
+         if (handled)
+            *ret = 1;
+         else
+            *ret = 0;
+         return handled;
+      }
 
       default:
          VG_(message)(
@@ -5783,6 +5975,22 @@ static void mc_fini ( Int exitcode )
    }
 }
 
+/* mark the given addr/len unaddressable for watchpoint implementation
+   The PointKind will be handled at access time */
+static Bool mc_mark_unaddressable_for_watchpoint (PointKind kind, Bool insert,
+                                                  Addr addr, SizeT len)
+{
+   /* GDBTD this is somewhat fishy. We might rather have to save the previous
+      accessibility and definedness in gdbserver so as to allow restoring it
+      properly. Currently, we assume that the user only watches things
+      which are properly addressable and defined */
+   if (insert)
+      MC_(make_mem_noaccess) (addr, len);
+   else
+      MC_(make_mem_defined)  (addr, len);
+   return True;
+}
+
 static void mc_pre_clo_init(void)
 {
    VG_(details_name)            ("Memcheck");
@@ -5791,7 +5999,7 @@ static void mc_pre_clo_init(void)
    VG_(details_copyright_author)(
       "Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.");
    VG_(details_bug_reports_to)  (VG_BUGS_TO);
-   VG_(details_avg_translation_sizeB) ( 556 );
+   VG_(details_avg_translation_sizeB) ( 640 );
 
    VG_(basic_tool_funcs)          (mc_post_clo_init,
                                    MC_(instrument),
@@ -5928,6 +6136,8 @@ static void mc_pre_clo_init(void)
    VG_(track_post_reg_write)                  ( mc_post_reg_write );
    VG_(track_post_reg_write_clientcall_return)( mc_post_reg_write_clientcall );
 
+   VG_(needs_watchpoint)          ( mc_mark_unaddressable_for_watchpoint );
+
    init_shadow_memory();
    MC_(malloc_list)  = VG_(HT_construct)( "MC_(malloc_list)" );
    MC_(mempool_list) = VG_(HT_construct)( "MC_(mempool_list)" );