Addressing the review comments. Tried to minimize any code duplication. Added 
full context.

http://reviews.llvm.org/D4527

Files:
  include/sanitizer/asan_interface.h
  lib/asan/asan_debugging.cc
  lib/asan/asan_globals.cc
  lib/asan/asan_interface_internal.h
  lib/asan/asan_report.cc
  lib/asan/asan_report.h
  test/asan/TestCases/debug_locate.cc
  test/asan/TestCases/debug_report.cc
Index: include/sanitizer/asan_interface.h
===================================================================
--- include/sanitizer/asan_interface.h
+++ include/sanitizer/asan_interface.h
@@ -62,6 +62,32 @@
   // Print the description of addr (useful when debugging in gdb).
   void __asan_describe_address(void *addr);
 
+  // Useful for calling from a debugger to get information about an ASan error.
+  // Returns 1 if an error has been (or is being) reported, otherwise returns 0.
+  int __asan_report_present();
+
+  // Useful for calling from a debugger to get information about an ASan error.
+  // If an error has been (or is being) reported, the following functions return
+  // the pc, bp, sp, address, access type (0 = read, 1 = write), access size and
+  // bug description (e.g. "heap-use-after-free"). Otherwise they return 0.
+  void *__asan_get_report_pc();
+  void *__asan_get_report_bp();
+  void *__asan_get_report_sp();
+  void *__asan_get_report_address();
+  int __asan_get_report_access_type();
+  size_t __asan_get_report_access_size();
+  const char *__asan_get_report_description();
+
+  // Useful for calling from the debugger to get information about a pointer.
+  // Returns the category of the given pointer as a constant string.
+  // Possible return values are "global", "stack", "stack-fake", "heap",
+  // "heap-invalid", "shadow-low", "shadow-gap", "shadow-high", "unknown".
+  // If global or stack, tries to also return the variable name, address and
+  // size. If heap, tries to return the chunk address and size. 'name' should
+  // point to an allocated buffer of size 'name_size'.
+  const char *__asan_locate_address(void *addr, char *name, size_t name_size,
+                                    void **region_address, size_t *region_size);
+
   // Useful for calling from the debugger to get the allocation stack trace
   // and thread ID for a heap address. Stores up to 'size' frames into 'trace',
   // returns the number of stored frames or 0 on error.
Index: lib/asan/asan_debugging.cc
===================================================================
--- lib/asan/asan_debugging.cc
+++ lib/asan/asan_debugging.cc
@@ -17,10 +17,70 @@
 #include "asan_flags.h"
 #include "asan_internal.h"
 #include "asan_mapping.h"
+#include "asan_report.h"
 #include "asan_thread.h"
 
 namespace __asan {
 
+void AsanGetStackVarInfo(uptr addr, char *name, uptr name_size,
+                         uptr *region_address, uptr *region_size,
+                         AsanThread *t) {
+  uptr offset = 0;
+  uptr frame_pc = 0;
+  const char *frame_descr = t->GetFrameNameByAddr(addr, &offset, &frame_pc);
+  InternalMmapVector<StackVarDescr> vars(16);
+  ParseFrameDescription(frame_descr, &vars);
+
+  for (uptr i = 0; i < vars.size(); i++) {
+    if (offset <= vars[i].beg + vars[i].size) {
+      if (name) {
+        uptr var_name_len = vars[i].name_len;
+        if (vars[i].name_len > name_size - 1) var_name_len = name_size - 1;
+        memcpy(name, vars[i].name_pos, var_name_len);
+        name[var_name_len] = '\0';
+      }
+      if (region_address) *region_address = addr - (offset - vars[i].beg);
+      if (region_size) *region_size = vars[i].size;
+      break;
+    }
+  }
+}
+
+const char *AsanLocateAddress(uptr addr, char *name, uptr name_size,
+                              uptr *region_address, uptr *region_size) {
+  // Check if addr is in shadow memory.
+  const char *stack_address_type = 0;
+  if (DescribeAddressIfShadow(addr, &stack_address_type, /* print */ false)) {
+    return stack_address_type;
+  }
+
+  // Check if addr is in global memory.
+  if (GetInfoForAddressIfGlobal(addr, name, name_size, region_address,
+                                region_size)) {
+    return "global";
+  }
+
+  // Check if addr is a pointer into a stack.
+  asanThreadRegistry().Lock();
+  AsanThread *thread = FindThreadByStackAddress(addr);
+  asanThreadRegistry().Unlock();
+  if (thread) {
+    AsanGetStackVarInfo(addr, name, name_size, region_address, region_size,
+                        thread);
+    return "stack";
+  }
+
+  // Let's assume addr is a heap address.
+  AsanChunkView chunk = FindHeapChunkByAddress(addr);
+  if (!chunk.IsValid())
+    return "heap-invalid";
+
+  if (region_address) *region_address = chunk.Beg();
+  if (region_size) *region_size = chunk.UsedSize();
+
+  return "heap";
+}
+
 uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id,
                   bool alloc_stack) {
   AsanChunkView chunk = FindHeapChunkByAddress(addr);
@@ -56,6 +116,12 @@
 using namespace __asan;
 
 SANITIZER_INTERFACE_ATTRIBUTE
+const char *__asan_locate_address(uptr addr, char *name, uptr name_size,
+                                  uptr *region_address, uptr *region_size) {
+  return AsanLocateAddress(addr, name, name_size, region_address, region_size);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
 uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
   return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ true);
 }
Index: lib/asan/asan_globals.cc
===================================================================
--- lib/asan/asan_globals.cc
+++ lib/asan/asan_globals.cc
@@ -82,19 +82,39 @@
   }
 }
 
-bool DescribeAddressIfGlobal(uptr addr, uptr size) {
+bool DescribeOrGetInfoIfGlobal(uptr addr, uptr size, bool only_get_info,
+                               char *name, uptr name_size, uptr *region_address,
+                               uptr *region_size) {
   if (!flags()->report_globals) return false;
   BlockingMutexLock lock(&mu_for_globals);
   bool res = false;
   for (ListOfGlobals *l = list_of_all_globals; l; l = l->next) {
     const Global &g = *l->g;
-    if (flags()->report_globals >= 2)
-      ReportGlobal(g, "Search");
-    res |= DescribeAddressRelativeToGlobal(addr, size, g);
+    if (only_get_info) {
+      if (GetInfoForAddressRelativeToGlobal(addr, g, name, name_size,
+                                          region_address, region_size)) {
+        return true;
+      }
+    } else {
+      if (flags()->report_globals >= 2)
+        ReportGlobal(g, "Search");
+      res |= DescribeAddressRelativeToGlobal(addr, size, g);
+    }
   }
   return res;
 }
 
+bool DescribeAddressIfGlobal(uptr addr, uptr size) {
+  return DescribeOrGetInfoIfGlobal(addr, size, /* only_get_info */ false, 0, 0,
+                                   0, 0);
+}
+
+bool GetInfoForAddressIfGlobal(uptr addr, char *name, uptr name_size,
+                               uptr *region_address, uptr *region_size) {
+  return DescribeOrGetInfoIfGlobal(addr, 1, /* only_get_info */ true, name,
+                                   name_size, region_address, region_size);
+}
+
 u32 FindRegistrationSite(const Global *g) {
   CHECK(global_registration_site_vector);
   for (uptr i = 0, n = global_registration_site_vector->size(); i < n; i++) {
Index: lib/asan/asan_interface_internal.h
===================================================================
--- lib/asan/asan_interface_internal.h
+++ lib/asan/asan_interface_internal.h
@@ -90,6 +90,41 @@
   SANITIZER_INTERFACE_ATTRIBUTE
   void __asan_describe_address(uptr addr);
 
+  // Returns 1 if an error has been (or is being) reported, otherwise returns 0.
+  SANITIZER_INTERFACE_ATTRIBUTE
+  int __asan_report_present();
+
+  // The following functions extract various information from a report (if a
+  // report has already been printed out or is currently being generated).
+  // For PC, BP, SP and memory address returns a pointer, for access type
+  // return 0 = read or 1 = write, for access size returns a number of bytes,
+  // and a string description of the report type (e.g. "heap-use-after-free").
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_pc();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_bp();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_sp();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_address();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  int __asan_get_report_access_type();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  uptr __asan_get_report_access_size();
+  SANITIZER_INTERFACE_ATTRIBUTE
+  const char * __asan_get_report_description();
+
+  // Useful for calling from the debugger to get information about a pointer.
+  // Returns the category of the given pointer as a constant string.
+  // Possible return values are "global", "stack", "stack-fake", "heap",
+  // "heap-invalid", "shadow-low", "shadow-gap", "shadow-high", "unknown".
+  // If global or stack, tries to also return the variable name, address and
+  // size. If heap, tries to return the chunk address and size. 'name' should
+  // point to an allocated buffer of size 'name_size'.
+  SANITIZER_INTERFACE_ATTRIBUTE
+  const char * __asan_locate_address(uptr addr, char *name, uptr name_size,
+                                     uptr *region_address, uptr *region_size);
+
   SANITIZER_INTERFACE_ATTRIBUTE
   uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size,
                               u32 *thread_id);
Index: lib/asan/asan_report.cc
===================================================================
--- lib/asan/asan_report.cc
+++ lib/asan/asan_report.cc
@@ -31,6 +31,19 @@
 static uptr error_message_buffer_pos = 0;
 static uptr error_message_buffer_size = 0;
 
+struct ReportData {
+  uptr pc;
+  uptr sp;
+  uptr bp;
+  uptr addr;
+  bool is_write;
+  uptr access_size;
+  const char *description;
+};
+
+static bool report_happened = false;
+static ReportData report_data = {};
+
 void AppendToErrorMessageBuffer(const char *buffer) {
   if (error_message_buffer) {
     uptr length = internal_strlen(buffer);
@@ -235,11 +248,17 @@
     str->append(":%d", g.location->column_no);
 }
 
-bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
-                                     const __asan_global &g) {
-  static const uptr kMinimalDistanceFromAnotherGlobal = 64;
+const uptr kMinimalDistanceFromAnotherGlobal = 64;
+
+bool IsAddressNearGlobal(uptr addr, const __asan_global &g) {
   if (addr <= g.beg - kMinimalDistanceFromAnotherGlobal) return false;
   if (addr >= g.beg + g.size_with_redzone) return false;
+  return true;
+}
+
+bool DescribeAddressRelativeToGlobal(uptr addr, uptr size,
+                                     const __asan_global &g) {
+  if (!IsAddressNearGlobal(addr, g)) return false;
   InternalScopedString str(4096);
   Decorator d;
   str.append("%s", d.Location());
@@ -265,21 +284,39 @@
   return true;
 }
 
-bool DescribeAddressIfShadow(uptr addr) {
+bool GetInfoForAddressRelativeToGlobal(uptr addr, const __asan_global &g,
+                                      char *name, uptr name_size,
+                                      uptr *region_address, uptr *region_size) {
+  if (!IsAddressNearGlobal(addr, g)) return false;
+  if (name) {
+    uptr name_len = strlen(g.name);
+    if (name_len > name_size - 1) name_len = name_size - 1;
+    memcpy(name, g.name, name_len);
+    name[name_len] = '\0';
+  }
+  if (region_address) *region_address = g.beg;
+  if (region_size) *region_size = g.size;
+  return true;
+}
+
+bool DescribeAddressIfShadow(uptr addr, const char **shadow_type, bool print) {
   if (AddrIsInMem(addr))
     return false;
   static const char kAddrInShadowReport[] =
       "Address %p is located in the %s.\n";
   if (AddrIsInShadowGap(addr)) {
-    Printf(kAddrInShadowReport, addr, "shadow gap area");
+    if (shadow_type) *shadow_type = "shadow-gap";
+    if (print) Printf(kAddrInShadowReport, addr, "shadow gap area");
     return true;
   }
   if (AddrIsInHighShadow(addr)) {
-    Printf(kAddrInShadowReport, addr, "high shadow area");
+    if (shadow_type) *shadow_type = "shadow-high";
+    if (print) Printf(kAddrInShadowReport, addr, "high shadow area");
     return true;
   }
   if (AddrIsInLowShadow(addr)) {
-    Printf(kAddrInShadowReport, addr, "low shadow area");
+    if (shadow_type) *shadow_type = "shadow-low";
+    if (print) Printf(kAddrInShadowReport, addr, "low shadow area");
     return true;
   }
   CHECK(0 && "Address is not in memory and not in shadow?");
@@ -893,8 +930,6 @@
 
 void __asan_report_error(uptr pc, uptr bp, uptr sp, uptr addr, int is_write,
                          uptr access_size) {
-  ScopedInErrorReport in_report;
-
   // Determine the error type.
   const char *bug_descr = "unknown-crash";
   if (AddrIsInMem(addr)) {
@@ -942,6 +977,18 @@
         break;
     }
   }
+
+  report_happened = true;
+  report_data.description = bug_descr;
+  report_data.pc = pc;
+  report_data.bp = bp;
+  report_data.sp = sp;
+  report_data.addr = addr;
+  report_data.is_write = is_write;
+  report_data.access_size = access_size;
+
+  ScopedInErrorReport in_report;
+
   Decorator d;
   Printf("%s", d.Warning());
   Report("ERROR: AddressSanitizer: %s on address "
@@ -983,6 +1030,38 @@
   asanThreadRegistry().Unlock();
 }
 
+int __asan_report_present() {
+  return report_happened ? 1 : 0;
+}
+
+uptr __asan_get_report_pc() {
+  return report_data.pc;
+}
+
+uptr __asan_get_report_bp() {
+  return report_data.bp;
+}
+
+uptr __asan_get_report_sp() {
+  return report_data.sp;
+}
+
+uptr __asan_get_report_address() {
+  return report_data.addr;
+}
+
+int __asan_get_report_access_type() {
+  return report_data.is_write ? 1 : 0;
+}
+
+uptr __asan_get_report_access_size() {
+  return report_data.access_size;
+}
+
+const char *__asan_get_report_description() {
+  return report_data.description;
+}
+
 extern "C" {
 SANITIZER_INTERFACE_ATTRIBUTE
 void __sanitizer_ptr_sub(void *a, void *b) {
Index: lib/asan/asan_report.h
===================================================================
--- lib/asan/asan_report.h
+++ lib/asan/asan_report.h
@@ -31,7 +31,13 @@
 bool DescribeAddressIfGlobal(uptr addr, uptr access_size);
 bool DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
                                      const __asan_global &g);
-bool DescribeAddressIfShadow(uptr addr);
+bool GetInfoForAddressRelativeToGlobal(uptr addr, const __asan_global &g,
+                                       char *name, uptr name_size,
+                                       uptr *region_address, uptr *region_size);
+bool GetInfoForAddressIfGlobal(uptr addr, char *name, uptr name_size,
+                               uptr *region_address, uptr *region_size);
+bool DescribeAddressIfShadow(uptr addr, const char **shadow_type = 0,
+                             bool print = true);
 bool ParseFrameDescription(const char *frame_descr,
                            InternalMmapVector<StackVarDescr> *vars);
 bool DescribeAddressIfStack(uptr addr, uptr access_size);
Index: test/asan/TestCases/debug_locate.cc
===================================================================
--- test/asan/TestCases/debug_locate.cc
+++ test/asan/TestCases/debug_locate.cc
@@ -0,0 +1,100 @@
+// Checks the ASan memory address type debugging API, makes sure it returns
+// the correct memory type for heap, stack, global and shadow addresses and
+// that it correctly finds out which region (and name and size) the address
+// belongs to.
+// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/asan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int global_var;
+
+int main() {
+  int local_var;
+  char *heap_ptr = (char *)malloc(10);
+
+  char name[100];
+  void *region_address;
+  size_t region_size;
+  const char *type;
+
+  type = __asan_locate_address(&global_var, name, 100,
+                               &region_address, &region_size);
+
+  printf("global: %s, %s, %s, %s\n",
+         name,
+         (strcmp(type, "global") == 0) ? "ok" : "ko",
+         (region_address == &global_var) ? "ok" : "ko",
+         (region_size == sizeof(global_var)) ? "ok" : "ko");
+  // CHECK: global: global_var, ok, ok, ok
+
+  type = __asan_locate_address((char *)(&global_var)+1, name, 100,
+                               &region_address, &region_size);
+
+  printf("global+1: %s, %s, %s, %s\n",
+         name,
+         (strcmp(type, "global") == 0) ? "ok" : "ko",
+         (region_address == &global_var) ? "ok" : "ko",
+         (region_size == sizeof(global_var)) ? "ok" : "ko");
+  // CHECK: global+1: global_var, ok, ok, ok
+
+  type = __asan_locate_address(&local_var, name, 100,
+                               &region_address, &region_size);
+
+  printf("local: %s, %s, %s, %s\n",
+         name,
+         (strcmp(type, "stack") == 0) ? "ok" : "ko",
+         (region_address == &local_var) ? "ok" : "ko",
+         (region_size == sizeof(local_var)) ? "ok" : "ko");
+  // CHECK: local: local_var, ok, ok, ok
+
+  type = __asan_locate_address((char *)(&local_var)+1, name, 100,
+                               &region_address, &region_size);
+
+  printf("local+1: %s, %s, %s, %s\n",
+         name,
+         (strcmp(type, "stack") == 0) ? "ok" : "ko",
+         (region_address == &local_var) ? "ok" : "ko",
+         (region_size == sizeof(local_var)) ? "ok" : "ko");
+  // CHECK: local+1: local_var, ok, ok, ok
+
+  type = __asan_locate_address(heap_ptr, name, 100,
+                               &region_address, &region_size);
+
+  printf("heap: %s, %s, %s\n",
+         (strcmp(type, "heap") == 0) ? "ok" : "ko",
+         (region_address == heap_ptr) ? "ok" : "ko",
+         (region_size == 10) ? "ok" : "ko");
+  // CHECK: heap: ok, ok, ok
+
+  type = __asan_locate_address(heap_ptr+1, name, 100,
+                               &region_address, &region_size);
+
+  printf("heap+1: %s, %s, %s\n",
+         (strcmp(type, "heap") == 0) ? "ok" : "ko",
+         (region_address == heap_ptr) ? "ok" : "ko",
+         (region_size == 10) ? "ok" : "ko");
+  // CHECK: heap+1: ok, ok, ok
+
+  size_t shadow_scale;
+  size_t shadow_offset;
+  __asan_get_shadow_mapping(&shadow_scale, &shadow_offset);
+
+  intptr_t shadow_ptr = (((intptr_t)heap_ptr) >> shadow_scale) + shadow_offset;
+
+  type = __asan_locate_address((void *)shadow_ptr, NULL, 0, NULL, NULL);
+  printf("shadow: %s\n",
+         (strcmp(type, "shadow-high") == 0 ||
+          strcmp(type, "shadow-low") == 0) ? "ok" : "ko");
+  // CHECK: shadow: ok
+
+  intptr_t shadow_gap = (shadow_ptr >> shadow_scale) + shadow_offset;
+  type = __asan_locate_address((void *)shadow_gap, NULL, 0, NULL, NULL);
+  printf("shadow gap: %s\n",
+         (strcmp(type, "shadow-gap") == 0) ? "ok" : "ko");
+  // CHECK: shadow gap: ok
+
+  return 0;
+}
Index: test/asan/TestCases/debug_report.cc
===================================================================
--- test/asan/TestCases/debug_report.cc
+++ test/asan/TestCases/debug_report.cc
@@ -0,0 +1,48 @@
+// Checks that the ASan debugging API for getting report information
+// returns correct values.
+// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s
+
+#include <sanitizer/asan_interface.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+  char *heap_ptr = (char *)malloc(10);
+  free(heap_ptr);
+  int present = __asan_report_present();
+  fprintf(stderr, "%s\n", (present == 0) ? "no report" : "");
+  // CHECK: no report
+  heap_ptr[0] = 'A'; // BOOM
+  return 0;
+}
+
+void __asan_on_error() {
+  int present = __asan_report_present();
+  void *pc = __asan_get_report_pc();
+  void *bp = __asan_get_report_bp();
+  void *sp = __asan_get_report_sp();
+  void *addr = __asan_get_report_address();
+  int is_write = __asan_get_report_access_type();
+  size_t access_size = __asan_get_report_access_size();
+  const char *description = __asan_get_report_description();
+
+  fprintf(stderr, "%s\n", (present == 1) ? "report" : "");
+  // CHECK: report
+  fprintf(stderr, "pc: %p\n", pc);
+  // CHECK: pc: 0x[[PC:[0-9a-f]+]]
+  fprintf(stderr, "bp: %p\n", bp);
+  // CHECK: bp: 0x[[BP:[0-9a-f]+]]
+  fprintf(stderr, "sp: %p\n", sp);
+  // CHECK: sp: 0x[[SP:[0-9a-f]+]]
+  fprintf(stderr, "addr: %p\n", addr);
+  // CHECK: addr: 0x[[ADDR:[0-9a-f]+]]
+  fprintf(stderr, "type: %s\n", (is_write ? "write" : "read"));
+  // CHECK: type: write
+  fprintf(stderr, "access_size: %ld\n", access_size);
+  // CHECK: access_size: 1
+  fprintf(stderr, "description: %s\n", description);
+  // CHECK: description: heap-use-after-free
+}
+
+// CHECK: AddressSanitizer: heap-use-after-free on address {{0x0*}}[[ADDR]] at pc {{0x0*}}[[PC]] bp {{0x0*}}[[BP]] sp {{0x0*}}[[SP]]
+// CHECK: WRITE of size 1 at {{0x0*}}[[ADDR]] thread T0
_______________________________________________
lldb-commits mailing list
lldb-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/lldb-commits

Reply via email to