Coverage for /Syzygy/agent/asan/asan_rtl_impl.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
70.9%1752470.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/agent/asan/asan_rtl_impl.h"
  16    :  
  17    :  #include "base/bind.h"
  18    :  #include "base/logging.h"
  19    :  #include "base/debug/alias.h"
  20    :  #include "syzygy/agent/asan/asan_heap.h"
  21    :  #include "syzygy/agent/asan/asan_runtime.h"
  22    :  #include "syzygy/agent/asan/asan_shadow.h"
  23    :  
  24    :  namespace {
  25    :  
  26    :  using agent::asan::AsanErrorInfo;
  27    :  using agent::asan::AsanRuntime;
  28    :  using agent::asan::HeapProxy;
  29    :  
  30    :  HANDLE process_heap = NULL;
  31    :  
  32    :  // The asan runtime manager.
  33    :  AsanRuntime* asan_runtime = NULL;
  34    :  
  35    :  }  // namespace
  36    :  
  37    :  namespace agent {
  38    :  namespace asan {
  39    :  
  40  E :  void SetUpRtl(AsanRuntime* runtime) {
  41  E :    DCHECK(runtime != NULL);
  42  E :    asan_runtime = runtime;
  43  E :    process_heap = GetProcessHeap();
  44  E :  }
  45    :  
  46  E :  void TearDownRtl() {
  47  E :    process_heap = NULL;
  48  E :  }
  49    :  
  50    :  }  // namespace asan
  51    :  }  // namespace agent
  52    :  
  53    :  extern "C" {
  54    :  
  55    :  HANDLE WINAPI asan_HeapCreate(DWORD options,
  56    :                                SIZE_T initial_size,
  57  E :                                SIZE_T maximum_size) {
  58  E :    DCHECK(asan_runtime != NULL);
  59    :    scoped_ptr<HeapProxy> proxy(new HeapProxy(asan_runtime->stack_cache(),
  60  E :                                              asan_runtime->logger()));
  61  E :    if (!proxy->Create(options, initial_size, maximum_size))
  62  E :      return NULL;
  63    :  
  64  E :    asan_runtime->AddHeap(proxy.get());
  65    :  
  66  E :    return HeapProxy::ToHandle(proxy.release());
  67  E :  }
  68    :  
  69  E :  BOOL WINAPI asan_HeapDestroy(HANDLE heap) {
  70  E :    DCHECK(process_heap != NULL);
  71  E :    if (heap == process_heap)
  72  i :      return ::HeapDestroy(heap);
  73    :  
  74  E :    HeapProxy* proxy = HeapProxy::FromHandle(heap);
  75  E :    if (!proxy)
  76  i :      return FALSE;
  77    :  
  78  E :    asan_runtime->RemoveHeap(proxy);
  79    :  
  80  E :    if (proxy->Destroy()) {
  81  E :      delete proxy;
  82  E :      return TRUE;
  83    :    }
  84    :  
  85  i :    return FALSE;
  86  E :  }
  87    :  
  88    :  LPVOID WINAPI asan_HeapAlloc(HANDLE heap,
  89    :                               DWORD flags,
  90  E :                               SIZE_T bytes) {
  91  E :    DCHECK(process_heap != NULL);
  92  E :    if (heap == process_heap)
  93  i :      return ::HeapAlloc(heap, flags, bytes);
  94    :  
  95  E :    HeapProxy* proxy = HeapProxy::FromHandle(heap);
  96  E :    if (!proxy)
  97  i :      return NULL;
  98    :  
  99  E :    return proxy->Alloc(flags, bytes);
 100  E :  }
 101    :  
 102    :  LPVOID WINAPI asan_HeapReAlloc(HANDLE heap,
 103    :                                 DWORD flags,
 104    :                                 LPVOID mem,
 105  E :                                 SIZE_T bytes) {
 106  E :    DCHECK(process_heap != NULL);
 107  E :    if (heap == process_heap)
 108  i :      return ::HeapReAlloc(heap, flags, mem, bytes);
 109    :  
 110  E :    HeapProxy* proxy = HeapProxy::FromHandle(heap);
 111  E :    if (!proxy)
 112  i :      return NULL;
 113    :  
 114  E :    return proxy->ReAlloc(flags, mem, bytes);
 115  E :  }
 116    :  
 117    :  BOOL WINAPI asan_HeapFree(HANDLE heap,
 118    :                            DWORD flags,
 119  E :                            LPVOID mem) {
 120  E :    DCHECK(process_heap != NULL);
 121  E :    if (heap == process_heap)
 122  i :      return ::HeapFree(heap, flags, mem);
 123    :  
 124  E :    HeapProxy* proxy = HeapProxy::FromHandle(heap);
 125  E :    if (!proxy)
 126  i :      return FALSE;
 127    :  
 128  E :    if (!proxy->Free(flags, mem)) {
 129    :      CONTEXT context;
 130  E :      ::RtlCaptureContext(&context);
 131  E :      AsanErrorInfo error_info = {};
 132  E :      error_info.error_type = HeapProxy::UNKNOWN_BAD_ACCESS;
 133  E :      asan_runtime->OnError(&context, &error_info);
 134  E :      return false;
 135    :    }
 136    :  
 137  E :    return true;
 138  E :  }
 139    :  
 140    :  SIZE_T WINAPI asan_HeapSize(HANDLE heap,
 141    :                              DWORD flags,
 142  E :                              LPCVOID mem) {
 143  E :    DCHECK(process_heap != NULL);
 144  E :    if (heap == process_heap)
 145  i :      return ::HeapSize(heap, flags, mem);
 146    :  
 147  E :    HeapProxy* proxy = HeapProxy::FromHandle(heap);
 148  E :    if (!proxy)
 149  i :      return -1;
 150    :  
 151  E :    return proxy->Size(flags, mem);
 152  E :  }
 153    :  
 154    :  BOOL WINAPI asan_HeapValidate(HANDLE heap,
 155    :                                DWORD flags,
 156  E :                                LPCVOID mem) {
 157  E :    DCHECK(process_heap != NULL);
 158  E :    if (heap == process_heap)
 159  i :      return ::HeapValidate(heap, flags, mem);
 160    :  
 161  E :    HeapProxy* proxy = HeapProxy::FromHandle(heap);
 162  E :    if (!proxy)
 163  i :      return FALSE;
 164    :  
 165  E :    return proxy->Validate(flags, mem);
 166  E :  }
 167    :  
 168    :  SIZE_T WINAPI asan_HeapCompact(HANDLE heap,
 169  E :                                 DWORD flags) {
 170  E :    DCHECK(process_heap != NULL);
 171  E :    if (heap == process_heap)
 172  i :      return ::HeapCompact(heap, flags);
 173    :  
 174  E :    HeapProxy* proxy = HeapProxy::FromHandle(heap);
 175  E :    if (!proxy)
 176  i :      return 0;
 177    :  
 178  E :    return proxy->Compact(flags);
 179  E :  }
 180    :  
 181  E :  BOOL WINAPI asan_HeapLock(HANDLE heap) {
 182  E :    DCHECK(process_heap != NULL);
 183  E :    if (heap == process_heap)
 184  i :      return ::HeapLock(heap);
 185    :  
 186  E :    HeapProxy* proxy = HeapProxy::FromHandle(heap);
 187  E :    if (!proxy)
 188  i :      return FALSE;
 189    :  
 190  E :    return proxy->Lock();
 191  E :  }
 192    :  
 193  E :  BOOL WINAPI asan_HeapUnlock(HANDLE heap) {
 194  E :    DCHECK(process_heap != NULL);
 195  E :    if (heap == process_heap)
 196  i :      return ::HeapUnlock(heap);
 197    :  
 198  E :    HeapProxy* proxy = HeapProxy::FromHandle(heap);
 199  E :    if (!proxy)
 200  i :      return FALSE;
 201    :  
 202  E :    return proxy->Unlock();
 203  E :  }
 204    :  
 205    :  BOOL WINAPI asan_HeapWalk(HANDLE heap,
 206  E :                            LPPROCESS_HEAP_ENTRY entry) {
 207  E :    DCHECK(process_heap != NULL);
 208  E :    if (heap == process_heap)
 209  i :      return ::HeapWalk(heap, entry);
 210    :  
 211  E :    HeapProxy* proxy = HeapProxy::FromHandle(heap);
 212  E :    if (!proxy)
 213  i :      return FALSE;
 214    :  
 215  E :    return proxy->Walk(entry);
 216  E :  }
 217    :  
 218    :  BOOL WINAPI asan_HeapSetInformation(
 219    :      HANDLE heap, HEAP_INFORMATION_CLASS info_class,
 220  E :      PVOID info, SIZE_T info_length) {
 221  E :    DCHECK(process_heap != NULL);
 222  E :    if (heap == NULL || heap == process_heap)
 223  E :      return ::HeapSetInformation(heap, info_class, info, info_length);
 224    :  
 225  E :    HeapProxy* proxy = HeapProxy::FromHandle(heap);
 226  E :    if (!proxy)
 227  i :      return FALSE;
 228    :  
 229  E :    return proxy->SetInformation(info_class, info, info_length);
 230  E :  }
 231    :  
 232    :  BOOL WINAPI asan_HeapQueryInformation(
 233    :      HANDLE heap, HEAP_INFORMATION_CLASS info_class,
 234  E :      PVOID info, SIZE_T info_length, PSIZE_T return_length) {
 235  E :    DCHECK(process_heap != NULL);
 236  E :    if (heap == NULL || heap == process_heap) {
 237    :      return ::HeapQueryInformation(heap,
 238    :                                    info_class,
 239    :                                    info,
 240    :                                    info_length,
 241  i :                                    return_length);
 242    :    }
 243    :  
 244  E :    HeapProxy* proxy = HeapProxy::FromHandle(heap);
 245  E :    if (!proxy)
 246  i :      return FALSE;
 247    :  
 248    :    bool ret = proxy->QueryInformation(info_class,
 249    :                                       info,
 250    :                                       info_length,
 251  E :                                       return_length);
 252  E :    return ret == true;
 253  E :  }
 254    :  
 255  E :  void WINAPI asan_SetCallBack(AsanErrorCallBack callback) {
 256  E :    DCHECK(asan_runtime != NULL);
 257  E :    asan_runtime->SetErrorCallBack(base::Bind(callback));
 258  E :  }
 259    :  
 260    :  }  // extern "C"
 261    :  
 262    :  namespace agent {
 263    :  namespace asan {
 264    :  
 265    :  // Contents of the registers before calling the ASAN memory check function.
 266    :  #pragma pack(push, 1)
 267    :  struct AsanContext {
 268    :    DWORD original_edi;
 269    :    DWORD original_esi;
 270    :    DWORD original_ebp;
 271    :    DWORD original_esp;
 272    :    DWORD original_ebx;
 273    :    DWORD original_edx;
 274    :    DWORD original_ecx;
 275    :    DWORD original_eax;
 276    :    DWORD original_eflags;
 277    :    DWORD original_eip;
 278    :  };
 279    :  #pragma pack(pop)
 280    :  
 281    :  // Report a bad access to the memory.
 282    :  // @param location The memory address of the access.
 283    :  // @param access_mode The mode of the access.
 284    :  // @param access_size The size of the access.
 285    :  // @param asan_context The context of the access.
 286    :  void ReportBadMemoryAccess(void* location,
 287    :                             HeapProxy::AccessMode access_mode,
 288    :                             size_t access_size,
 289  E :                             struct AsanContext* asan_context) {
 290    :    // Capture the context and restore the value of the register as before calling
 291    :    // the asan hook.
 292    :  
 293    :    // Capture the current context.
 294  E :    CONTEXT context = {};
 295    :  
 296    :    // We need to call ::RtlCaptureContext if we want SegSS and SegCS to be
 297    :    // properly set.
 298  E :    ::RtlCaptureContext(&context);
 299  E :    context.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
 300    :  
 301    :    // Restore the original value of the registers.
 302  E :    context.Eip = asan_context->original_eip;
 303  E :    context.Eax = asan_context->original_eax;
 304  E :    context.Ecx = asan_context->original_ecx;
 305  E :    context.Edx = asan_context->original_edx;
 306  E :    context.Ebx = asan_context->original_ebx;
 307  E :    context.Ebp = asan_context->original_ebp;
 308  E :    context.Esp = asan_context->original_esp;
 309  E :    context.Esi = asan_context->original_esi;
 310  E :    context.Edi = asan_context->original_edi;
 311  E :    context.EFlags = asan_context->original_eflags;
 312    :  
 313  E :    StackCapture stack;
 314  E :    stack.InitFromStack();
 315    :    // We need to compute a relative stack id so that for the same stack trace
 316    :    // we'll get the same value every time even if the modules are loaded at a
 317    :    // different base address.
 318  E :    stack.set_stack_id(stack.ComputeRelativeStackId());
 319    :  
 320    :    // Check if we can ignore this error.
 321  E :    if (asan_runtime->ShouldIgnoreError(stack.stack_id()))
 322  i :      return;
 323    :  
 324    :    // We keep a structure with all the useful information about this bad access
 325    :    // on the stack.
 326  E :    AsanErrorInfo bad_access_info = {};
 327  E :    bad_access_info.access_mode = access_mode;
 328  E :    bad_access_info.access_size = access_size;
 329  E :    bad_access_info.alloc_stack_size = 0U;
 330  E :    bad_access_info.alloc_tid = 0U;
 331  E :    bad_access_info.error_type = HeapProxy::UNKNOWN_BAD_ACCESS;
 332  E :    bad_access_info.free_stack_size = 0U;
 333  E :    bad_access_info.free_tid = 0U;
 334  E :    bad_access_info.microseconds_since_free = 0U;
 335    :  
 336    :    // Make sure this structure is not optimized out.
 337  E :    base::debug::Alias(&bad_access_info);
 338    :  
 339    :    asan_runtime->ReportAsanErrorDetails(location,
 340    :                                         context,
 341    :                                         stack,
 342    :                                         access_mode,
 343    :                                         access_size,
 344  E :                                         &bad_access_info);
 345    :  
 346    :    // Call the callback to handle this error.
 347  E :    asan_runtime->OnError(&context, &bad_access_info);
 348  E :  }
 349    :  
 350    :  // Check if the memory location is accessible and report an error on bad memory
 351    :  // accesses.
 352    :  // @param location The memory address of the access.
 353    :  // @param access_mode The mode of the access.
 354    :  // @param access_size The size of the access.
 355    :  // @param context The registers context of the access.
 356    :  void CheckMemoryAccess(void* location,
 357    :                         HeapProxy::AccessMode access_mode,
 358    :                         size_t access_size,
 359  E :                         AsanContext* context) {
 360  E :    if (!agent::asan::Shadow::IsAccessible(location))
 361  E :      ReportBadMemoryAccess(location, access_mode, access_size, context);
 362  E :  }
 363    :  
 364    :  // Check if the memory accesses done by a string instructions are valid.
 365    :  // @param dst The destination memory address of the access.
 366    :  // @param dst_access_mode The destination mode of the access.
 367    :  // @param src The source memory address of the access.
 368    :  // @param src_access_mode The source mode of the access.
 369    :  // @param length The number of memory accesses.
 370    :  // @param access_size The size of each the access in byte.
 371    :  // @param increment The increment to move dst/src after each access.
 372    :  // @param compare Flag to activate shortcut of the execution on difference.
 373    :  // @param context The registers context of the access.
 374    :  void CheckStringsMemoryAccesses(
 375    :      uint8* dst, HeapProxy::AccessMode dst_access_mode,
 376    :      uint8* src, HeapProxy::AccessMode src_access_mode,
 377    :      uint32 length, size_t access_size, int32 increment, bool compare,
 378  E :      AsanContext* context) {
 379  E :    int32 offset = 0;
 380    :  
 381  E :    for (uint32 i = 0; i < length; ++i) {
 382    :      // Check next memory location at src[offset].
 383  E :      if (src_access_mode != HeapProxy::ASAN_UNKNOWN_ACCESS)
 384  E :        CheckMemoryAccess(&src[offset], src_access_mode, access_size, context);
 385    :  
 386    :      // Check next memory location at dst[offset].
 387  E :      if (dst_access_mode != HeapProxy::ASAN_UNKNOWN_ACCESS)
 388  E :        CheckMemoryAccess(&dst[offset], dst_access_mode, access_size, context);
 389    :  
 390    :      // For CMPS instructions, we shortcut the execution of prefix REPZ when
 391    :      // memory contents differ.
 392  E :      if (compare) {
 393  E :        uint32 src_content = 0;
 394  E :        uint32 dst_content = 0;
 395  E :        switch (access_size) {
 396    :        case 4:
 397  E :          src_content = *reinterpret_cast<uint32*>(&src[offset]);
 398  E :          dst_content = *reinterpret_cast<uint32*>(&dst[offset]);
 399  E :          break;
 400    :        case 2:
 401  E :          src_content = *reinterpret_cast<uint16*>(&src[offset]);
 402  E :          dst_content = *reinterpret_cast<uint16*>(&dst[offset]);
 403  E :          break;
 404    :        case 1:
 405  E :          src_content = *reinterpret_cast<uint8*>(&src[offset]);
 406  E :          dst_content = *reinterpret_cast<uint8*>(&dst[offset]);
 407  E :          break;
 408    :        default:
 409  i :          NOTREACHED() << "Unexpected access_size.";
 410    :          break;
 411    :        }
 412    :  
 413  E :        if (src_content != dst_content)
 414  E :          return;
 415    :      }
 416    :  
 417    :      // Increments offset of dst/src to the next memory location.
 418  E :      offset += increment;
 419  E :    }
 420  E :  }
 421    :  
 422    :  }  // namespace asan
 423    :  }  // namespace agent
 424    :  
 425    :  // This is a trick for efficient saving/restoring part of the flags register.
 426    :  // see http://blog.freearrow.com/archives/396
 427    :  // Flags (bits 16-31) probably need a pipeline flush on update (POPFD). Thus,
 428    :  // using LAHF/SAHF instead gives better performance.
 429    :  //   PUSHFD/POPFD: 23.314684 ticks
 430    :  //   LAHF/SAHF:     8.838665 ticks
 431    :  
 432    :  // This macro starts by saving EAX onto the stack and then loads the value of
 433    :  // the flags into it.
 434    :  #define ASAN_SAVE_EFLAGS  \
 435    :      __asm push eax  \
 436    :      __asm lahf  \
 437    :      __asm seto al
 438    :  
 439    :  // This macro restores the flags, their previous value is assumed to be in EAX
 440    :  // and we expect to have the previous value of EAX on the top of the stack.
 441    :  // AL is set to 1 if the overflow flag was set before the call to our hook, 0
 442    :  // otherwise. We add 0x7f to it so it'll restore the flag. Then we restore the
 443    :  // low bytes of the flags and EAX.
 444    :  #define ASAN_RESTORE_EFLAGS  \
 445    :      __asm add al, 0x7f  \
 446    :      __asm sahf  \
 447    :      __asm pop eax
 448    :  
 449    :  // This is the common part of the fast path shared between the different
 450    :  // implementations of the hooks, this does the following:
 451    :  //     - Saves the memory location in EDX for the slow path.
 452    :  //     - Checks if the address we're trying to access is signed, if so this mean
 453    :  //         that this is an access to the upper region of the memory (over the
 454    :  //         2GB limit) and we should report this as an invalid wild access.
 455    :  //     - Checks for zero shadow for this memory location. We use the cmp
 456    :  //         instruction so it'll set the sign flag if the upper bit of the shadow
 457    :  //         value of this memory location is set to 1.
 458    :  //     - If the shadow byte is not equal to zero then it jumps to the slow path.
 459    :  //     - Otherwise it removes the memory location from the top of the stack.
 460    :  #define ASAN_FAST_PATH  \
 461    :      __asm push edx  \
 462    :      __asm sar edx, 3  \
 463    :      __asm js report_failure  \
 464    :      __asm movzx edx, BYTE PTR[edx + agent::asan::Shadow::shadow_]  \
 465    :      __asm cmp dl, 0  \
 466    :      __asm jnz check_access_slow  \
 467    :      __asm add esp, 4
 468    :  
 469    :  // This is the common part of the slow path shared between the different
 470    :  // implementations of the hooks. The memory location is expected to be on top of
 471    :  // the stack and the shadow value for it is assumed to be in DL at this point.
 472    :  // This also relies on the fact that the shadow non accessible byte mask has its
 473    :  // upper bit set to 1 and that we jump to this macro after doing a
 474    :  // "cmp shadow_byte, 0", so the sign flag would be set to 1 if the value isn't
 475    :  // accessible.
 476    :  // We inline the Shadow::IsAccessible function for performance reasons.
 477    :  // This function does the following:
 478    :  //     - Checks if this byte is accessible and jump to the error path if it's
 479    :  //       not.
 480    :  //     - Removes the memory location from the top of the stack.
 481    :  #define ASAN_SLOW_PATH  \
 482    :      __asm js report_failure  \
 483    :      __asm mov dh, BYTE PTR[esp]  \
 484    :      __asm and dh, 7  \
 485    :      __asm cmp dh, dl  \
 486    :      __asm jae report_failure  \
 487    :      __asm add esp, 4
 488    :  
 489    :  // This is the error path. It expects to have the previous value of EDX at
 490    :  // [ESP + 4] and the address of the faulty instruction at [ESP].
 491    :  // This macro take cares of saving and restoring the flags.
 492    :  #define ASAN_ERROR_PATH(access_size, access_mode_value)  \
 493    :      /* Restore original value of EDX, and put memory location on stack. */  \
 494    :      __asm xchg edx, DWORD PTR[esp + 4]  \
 495    :      /* Create an ASAN registers context on the stack. */  \
 496    :      __asm pushfd  \
 497    :      __asm pushad  \
 498    :      /* Fix the original value of ESP in the ASAN registers context. */  \
 499    :      /* Removing 12 bytes (e.g. EFLAGS / EIP / Original EDX). */  \
 500    :      __asm add DWORD PTR[esp + 12], 12  \
 501    :      /* Push ARG4: the address of ASAN context on stack. */  \
 502    :      __asm push esp  \
 503    :      /* Push ARG3: the access size. */  \
 504    :      __asm push access_size  \
 505    :      /* Push ARG2: the access type. */  \
 506    :      __asm push access_mode_value  \
 507    :      /* Push ARG1: the memory location. */  \
 508    :      __asm push DWORD PTR[esp + 52]  \
 509    :      __asm call agent::asan::ReportBadMemoryAccess  \
 510    :      /* Remove 4 x ARG on stack. */  \
 511    :      __asm add esp, 16  \
 512    :      /* Restore original registers. */  \
 513    :      __asm popad  \
 514    :      __asm popfd  \
 515    :      /* Return and remove memory location on stack. */  \
 516    :      __asm ret 4
 517    :  
 518    :  // Generates the asan check access functions. The name of the generated method
 519    :  // will be asan_check_(@p access_size)_byte_(@p access_mode_str)().
 520    :  // @param access_size The size of the access (in byte).
 521    :  // @param access_mode_str The string representing the access mode (read_access
 522    :  //     or write_access).
 523    :  // @param access_mode_value The internal value representing this kind of access.
 524    :  // @note Calling this function doesn't alter any register.
 525    :  #define ASAN_CHECK_FUNCTION(access_size, access_mode_str, access_mode_value)  \
 526    :    extern "C" __declspec(naked)  \
 527    :        void asan_check_ ## access_size ## _byte_ ## access_mode_str ## () {  \
 528    :      __asm {  \
 529    :        /* Save the EFLAGS. */  \
 530    :        ASAN_SAVE_EFLAGS  \
 531    :        ASAN_FAST_PATH  \
 532    :        /* Restore original EDX. */  \
 533    :        __asm mov edx, DWORD PTR[esp + 8]  \
 534    :        /* Restore the EFLAGS. */  \
 535    :        ASAN_RESTORE_EFLAGS  \
 536    :        __asm ret 4  \
 537    :      __asm check_access_slow:  \
 538    :        ASAN_SLOW_PATH  \
 539    :        /* Restore original EDX. */  \
 540    :        __asm mov edx, DWORD PTR[esp + 8]  \
 541    :        /* Restore the EFLAGS. */  \
 542    :        ASAN_RESTORE_EFLAGS  \
 543    :        __asm ret 4  \
 544    :      __asm report_failure:  \
 545    :        /* Restore memory location in EDX. */  \
 546    :        __asm pop edx  \
 547    :        /* Restore the EFLAGS. */  \
 548    :        ASAN_RESTORE_EFLAGS  \
 549    :        ASAN_ERROR_PATH(access_size, access_mode_value)  \
 550    :      }  \
 551    :    }
 552    :  
 553    :  // Generates a variant of the asan check access functions that don't save the
 554    :  // flags. The name of the generated method will be
 555    :  // asan_check_(@p access_size)_byte_(@p access_mode_str)_no_flags().
 556    :  // @param access_size The size of the access (in byte).
 557    :  // @param access_mode_str The string representing the access mode (read_access
 558    :  //     or write_access).
 559    :  // @param access_mode_value The internal value representing this kind of access.
 560    :  // @note Calling this function may alter the EFLAGS register only.
 561    :  #define ASAN_CHECK_FUNCTION_NO_FLAGS(access_size,  \
 562    :                                       access_mode_str,  \
 563    :                                       access_mode_value)  \
 564    :    extern "C" __declspec(naked)  \
 565    :        void asan_check_ ## access_size ## _byte_ ## access_mode_str ##  \
 566    :            _no_flags() {  \
 567    :      __asm {  \
 568    :        ASAN_FAST_PATH  \
 569    :        /* Restore original EDX. */  \
 570    :        __asm mov edx, DWORD PTR[esp + 4]  \
 571    :        __asm ret 4  \
 572    :      __asm check_access_slow:  \
 573    :        ASAN_SLOW_PATH  \
 574    :        /* Restore original EDX. */  \
 575    :        __asm mov edx, DWORD PTR[esp + 4]  \
 576    :        __asm ret 4  \
 577    :      __asm report_failure:  \
 578    :        /* Restore memory location in EDX. */  \
 579    :        __asm pop edx  \
 580    :        ASAN_ERROR_PATH(access_size, access_mode_value)  \
 581    :      }  \
 582    :    }
 583    :  
 584    :  // Redefine some enums to make them accessible in the inlined assembly.
 585    :  // @{
 586    :  enum AccessMode {
 587    :    AsanReadAccess = HeapProxy::ASAN_READ_ACCESS,
 588    :    AsanWriteAccess = HeapProxy::ASAN_WRITE_ACCESS,
 589    :    AsanUnknownAccess = HeapProxy::ASAN_UNKNOWN_ACCESS,
 590    :  };
 591    :  // @}
 592    :  
 593    :  // The slow path rely on the fact that the shadow memory non accessible byte
 594    :  // mask have its upper bit set to 1..
 595    :  COMPILE_ASSERT(
 596    :      (agent::asan::Shadow::kHeapNonAccessibleByteMask & (1 << 7)) != 0,
 597    :          asan_shadow_mask_upper_bit_is_0);
 598    :  
 599  i :  ASAN_CHECK_FUNCTION(1, read_access, AsanReadAccess)
 600  i :  ASAN_CHECK_FUNCTION(2, read_access, AsanReadAccess)
 601  i :  ASAN_CHECK_FUNCTION(4, read_access, AsanReadAccess)
 602  i :  ASAN_CHECK_FUNCTION(8, read_access, AsanReadAccess)
 603  i :  ASAN_CHECK_FUNCTION(10, read_access, AsanReadAccess)
 604  i :  ASAN_CHECK_FUNCTION(16, read_access, AsanReadAccess)
 605  i :  ASAN_CHECK_FUNCTION(32, read_access, AsanReadAccess)
 606  i :  ASAN_CHECK_FUNCTION(1, write_access, AsanWriteAccess)
 607  i :  ASAN_CHECK_FUNCTION(2, write_access, AsanWriteAccess)
 608  i :  ASAN_CHECK_FUNCTION(4, write_access, AsanWriteAccess)
 609  i :  ASAN_CHECK_FUNCTION(8, write_access, AsanWriteAccess)
 610  i :  ASAN_CHECK_FUNCTION(10, write_access, AsanWriteAccess)
 611  i :  ASAN_CHECK_FUNCTION(16, write_access, AsanWriteAccess)
 612  i :  ASAN_CHECK_FUNCTION(32, write_access, AsanWriteAccess)
 613    :  
 614    :  #undef ASAN_CHECK_FUNCTION
 615    :  
 616  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(1, read_access, AsanReadAccess)
 617  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(2, read_access, AsanReadAccess)
 618  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(4, read_access, AsanReadAccess)
 619  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(8, read_access, AsanReadAccess)
 620  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(10, read_access, AsanReadAccess)
 621  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(16, read_access, AsanReadAccess)
 622  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(32, read_access, AsanReadAccess)
 623  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(1, write_access, AsanWriteAccess)
 624  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(2, write_access, AsanWriteAccess)
 625  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(4, write_access, AsanWriteAccess)
 626  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(8, write_access, AsanWriteAccess)
 627  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(10, write_access, AsanWriteAccess)
 628  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(16, write_access, AsanWriteAccess)
 629  i :  ASAN_CHECK_FUNCTION_NO_FLAGS(32, write_access, AsanWriteAccess)
 630    :  
 631    :  #undef ASAN_CHECK_FUNCTION_NO_FLAGS
 632    :  #undef ASAN_SAVE_EFLAGS
 633    :  #undef ASAN_RESTORE_EFLAGS
 634    :  #undef ASAN_FAST_PATH
 635    :  #undef ASAN_SLOW_PATH
 636    :  #undef ASAN_ERROR_PATH
 637    :  
 638    :  // Generates the asan check access functions for a string instruction.
 639    :  // The name of the generated method will be
 640    :  // asan_check_(@p prefix)(@p access_size)_byte_(@p inst)_access().
 641    :  // @param inst The instruction mnemonic.
 642    :  // @param prefix The prefix of the instruction (repz or nothing).
 643    :  // @param counter The number of times the instruction must be executed (ECX). It
 644    :  //     may be a register or a constant.
 645    :  // @param dst_mode The memory access mode for destination (EDI).
 646    :  // @param src_mode The memory access mode for destination (ESI).
 647    :  // @param access_size The size of the access (in byte).
 648    :  // @param compare A flag to enable shortcut execution by comparing memory
 649    :  //     contents.
 650    :  #define ASAN_CHECK_STRINGS(func, prefix, counter, dst_mode, src_mode, \
 651    :      access_size, compare)  \
 652    :    extern "C" __declspec(naked)  \
 653    :    void asan_check ## prefix ## access_size ## _byte_ ## func ## _access() {  \
 654    :      __asm {  \
 655    :        /* Prologue, save context. */  \
 656    :        __asm pushfd  \
 657    :        __asm pushad  \
 658    :        /* Fix the original value of ESP in the ASAN registers context. */  \
 659    :        /* Removing 8 bytes (e.g.EFLAGS / EIP was on stack). */  \
 660    :        __asm add DWORD PTR[esp + 12], 8  \
 661    :        /* Setup increment in EBX (depends on direction flag in EFLAGS). */  \
 662    :        __asm mov ebx, access_size  \
 663    :        __asm pushfd  \
 664    :        __asm pop eax  \
 665    :        __asm test eax, 0x400  \
 666    :        __asm jz skip_neg_direction  \
 667    :        __asm neg ebx  \
 668    :      __asm skip_neg_direction:  \
 669    :        /* By standard calling convention, direction flag must be forward. */  \
 670    :        __asm cld  \
 671    :        /* Push ARG(context), the ASAN registers context. */  \
 672    :        __asm push esp  \
 673    :        /* Push ARG(compare), shortcut when memory contents differ. */  \
 674    :        __asm push compare  \
 675    :        /* Push ARG(increment), increment for EDI/EDI. */  \
 676    :        __asm push ebx  \
 677    :        /* Push ARG(access_size), the access size. */  \
 678    :        __asm push access_size  \
 679    :        /* Push ARG(length), the number of memory accesses. */  \
 680    :        __asm push counter  \
 681    :        /* Push ARG(src_access_mode), source access type. */  \
 682    :        __asm push src_mode \
 683    :        /* Push ARG(src), the source pointer. */  \
 684    :        __asm push esi  \
 685    :        /* Push ARG(dst_access_mode), destination access type. */  \
 686    :        __asm push dst_mode \
 687    :        /* Push ARG(dst), the destination pointer. */  \
 688    :        __asm push edi  \
 689    :        /* Call the generic check strings function. */  \
 690    :        __asm call agent::asan::CheckStringsMemoryAccesses  \
 691    :        __asm add esp, 36  \
 692    :        /* Epilogue, restore context. */  \
 693    :        __asm popad  \
 694    :        __asm popfd  \
 695    :        __asm ret  \
 696    :      }  \
 697    :    }
 698    :  
 699  i :  ASAN_CHECK_STRINGS(cmps, _repz_, ecx, AsanReadAccess, AsanReadAccess, 4, 1)
 700  i :  ASAN_CHECK_STRINGS(cmps, _repz_, ecx, AsanReadAccess, AsanReadAccess, 2, 1)
 701  i :  ASAN_CHECK_STRINGS(cmps, _repz_, ecx, AsanReadAccess, AsanReadAccess, 1, 1)
 702  i :  ASAN_CHECK_STRINGS(cmps, _, 1, AsanReadAccess, AsanReadAccess, 4, 1)
 703  i :  ASAN_CHECK_STRINGS(cmps, _, 1, AsanReadAccess, AsanReadAccess, 2, 1)
 704  i :  ASAN_CHECK_STRINGS(cmps, _, 1, AsanReadAccess, AsanReadAccess, 1, 1)
 705    :  
 706  i :  ASAN_CHECK_STRINGS(movs, _repz_, ecx, AsanWriteAccess, AsanReadAccess, 4, 0)
 707  i :  ASAN_CHECK_STRINGS(movs, _repz_, ecx, AsanWriteAccess, AsanReadAccess, 2, 0)
 708  i :  ASAN_CHECK_STRINGS(movs, _repz_, ecx, AsanWriteAccess, AsanReadAccess, 1, 0)
 709  i :  ASAN_CHECK_STRINGS(movs, _, 1, AsanWriteAccess, AsanReadAccess, 4, 0)
 710  i :  ASAN_CHECK_STRINGS(movs, _, 1, AsanWriteAccess, AsanReadAccess, 2, 0)
 711  i :  ASAN_CHECK_STRINGS(movs, _, 1, AsanWriteAccess, AsanReadAccess, 1, 0)
 712    :  
 713  i :  ASAN_CHECK_STRINGS(stos, _repz_, ecx, AsanWriteAccess, AsanUnknownAccess, 4, 0)
 714  i :  ASAN_CHECK_STRINGS(stos, _repz_, ecx, AsanWriteAccess, AsanUnknownAccess, 2, 0)
 715  i :  ASAN_CHECK_STRINGS(stos, _repz_, ecx, AsanWriteAccess, AsanUnknownAccess, 1, 0)
 716  i :  ASAN_CHECK_STRINGS(stos, _, 1, AsanWriteAccess, AsanUnknownAccess, 4, 0)
 717  i :  ASAN_CHECK_STRINGS(stos, _, 1, AsanWriteAccess, AsanUnknownAccess, 2, 0)
 718  i :  ASAN_CHECK_STRINGS(stos, _, 1, AsanWriteAccess, AsanUnknownAccess, 1, 0)
 719    :  
 720    :  #undef ASAN_CHECK_STRINGS

Coverage information generated Thu Jul 04 09:34:53 2013.