forked from OSchip/llvm-project
[ASan] Add ASan debugging API to get malloc/free stack traces and shadow memory mapping info
Reviewed at http://reviews.llvm.org/D4466 llvm-svn: 213080
This commit is contained in:
parent
8587711164
commit
58f44dce96
|
@ -62,6 +62,22 @@ extern "C" {
|
|||
// Print the description of addr (useful when debugging in gdb).
|
||||
void __asan_describe_address(void *addr);
|
||||
|
||||
// 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.
|
||||
size_t __asan_get_alloc_stack(void *addr, void **trace, size_t size,
|
||||
int *thread_id);
|
||||
|
||||
// Useful for calling from the debugger to get the free 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.
|
||||
size_t __asan_get_free_stack(void *addr, void **trace, size_t size,
|
||||
int *thread_id);
|
||||
|
||||
// Useful for calling from the debugger to get the current shadow memory
|
||||
// mapping.
|
||||
void __asan_get_shadow_mapping(size_t *shadow_scale, size_t *shadow_offset);
|
||||
|
||||
// This is an internal function that is called to report an error.
|
||||
// However it is still a part of the interface because users may want to
|
||||
// set a breakpoint on this function in a debugger.
|
||||
|
|
|
@ -10,6 +10,7 @@ endif()
|
|||
set(ASAN_SOURCES
|
||||
asan_allocator2.cc
|
||||
asan_activation.cc
|
||||
asan_debugging.cc
|
||||
asan_fake_stack.cc
|
||||
asan_globals.cc
|
||||
asan_interceptors.cc
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
//===-- asan_debugging.cc -------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file is a part of AddressSanitizer, an address sanity checker.
|
||||
//
|
||||
// This file contains various functions that are generally useful to call when
|
||||
// using a debugger (LLDB, GDB).
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "asan_allocator.h"
|
||||
#include "asan_flags.h"
|
||||
#include "asan_internal.h"
|
||||
#include "asan_mapping.h"
|
||||
#include "asan_thread.h"
|
||||
|
||||
namespace __asan {
|
||||
|
||||
uptr AsanGetStack(uptr addr, uptr *trace, uptr size, u32 *thread_id,
|
||||
bool alloc_stack) {
|
||||
AsanChunkView chunk = FindHeapChunkByAddress(addr);
|
||||
if (!chunk.IsValid()) return 0;
|
||||
|
||||
StackTrace stack;
|
||||
if (alloc_stack) {
|
||||
if (chunk.AllocTid() == kInvalidTid) return 0;
|
||||
chunk.GetAllocStack(&stack);
|
||||
if (thread_id) *thread_id = chunk.AllocTid();
|
||||
} else {
|
||||
if (chunk.FreeTid() == kInvalidTid) return 0;
|
||||
chunk.GetFreeStack(&stack);
|
||||
if (thread_id) *thread_id = chunk.FreeTid();
|
||||
}
|
||||
|
||||
if (trace && size) {
|
||||
if (size > kStackTraceMax)
|
||||
size = kStackTraceMax;
|
||||
if (size > stack.size)
|
||||
size = stack.size;
|
||||
for (uptr i = 0; i < size; i++)
|
||||
trace[i] = StackTrace::GetPreviousInstructionPc(stack.trace[i]);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace __asan
|
||||
|
||||
using namespace __asan;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size, u32 *thread_id) {
|
||||
return AsanGetStack(addr, trace, size, thread_id, /* alloc_stack */ false);
|
||||
}
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset) {
|
||||
if (shadow_scale)
|
||||
*shadow_scale = SHADOW_SCALE;
|
||||
if (shadow_offset)
|
||||
*shadow_offset = SHADOW_OFFSET;
|
||||
}
|
|
@ -90,6 +90,17 @@ extern "C" {
|
|||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_describe_address(uptr addr);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_get_alloc_stack(uptr addr, uptr *trace, uptr size,
|
||||
u32 *thread_id);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
uptr __asan_get_free_stack(uptr addr, uptr *trace, uptr size,
|
||||
u32 *thread_id);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_get_shadow_mapping(uptr *shadow_scale, uptr *shadow_offset);
|
||||
|
||||
SANITIZER_INTERFACE_ATTRIBUTE
|
||||
void __asan_report_error(uptr pc, uptr bp, uptr sp,
|
||||
uptr addr, int is_write, uptr access_size);
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// Checks that the debugging API returns correct shadow scale and offset.
|
||||
// RUN: %clangxx_asan -O %s -o %t
|
||||
// RUN: env ASAN_OPTIONS=verbosity=1 %run %t 2>&1 | FileCheck %s
|
||||
|
||||
#include <sanitizer/asan_interface.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// printed because of verbosity=1
|
||||
// CHECK: SHADOW_SCALE: [[SCALE:[0-9]+]]
|
||||
// CHECK: SHADOW_OFFSET: [[OFFSET:[0-9]+]]
|
||||
|
||||
int main() {
|
||||
size_t scale, offset;
|
||||
__asan_get_shadow_mapping(&scale, &offset);
|
||||
|
||||
fprintf(stderr, "scale: %lx\n", scale);
|
||||
fprintf(stderr, "offset: %lx\n", offset);
|
||||
|
||||
// CHECK: scale: [[SCALE]]
|
||||
// CHECK: offset: [[OFFSET]]
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
// Check that the stack trace debugging API works and returns correct
|
||||
// malloc and free stacks.
|
||||
// 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>
|
||||
|
||||
char *mem;
|
||||
void func1() {
|
||||
mem = (char *)malloc(10);
|
||||
}
|
||||
|
||||
void func2() {
|
||||
free(mem);
|
||||
}
|
||||
|
||||
int main() {
|
||||
func1();
|
||||
func2();
|
||||
|
||||
void *trace[100];
|
||||
size_t num_frames = 100;
|
||||
int thread_id;
|
||||
num_frames = __asan_get_alloc_stack(mem, trace, num_frames, &thread_id);
|
||||
|
||||
fprintf(stderr, "alloc stack retval %s\n", (num_frames > 0 && num_frames < 10)
|
||||
? "ok" : "");
|
||||
// CHECK: alloc stack retval ok
|
||||
fprintf(stderr, "thread id = %d\n", thread_id);
|
||||
// CHECK: thread id = 0
|
||||
fprintf(stderr, "0x%lx\n", trace[0]);
|
||||
// CHECK: [[ALLOC_FRAME_0:0x[0-9a-f]+]]
|
||||
fprintf(stderr, "0x%lx\n", trace[1]);
|
||||
// CHECK: [[ALLOC_FRAME_1:0x[0-9a-f]+]]
|
||||
|
||||
num_frames = 100;
|
||||
num_frames = __asan_get_free_stack(mem, trace, num_frames, &thread_id);
|
||||
|
||||
fprintf(stderr, "free stack retval %s\n", (num_frames > 0 && num_frames < 10)
|
||||
? "ok" : "");
|
||||
// CHECK: free stack retval ok
|
||||
fprintf(stderr, "thread id = %d\n", thread_id);
|
||||
// CHECK: thread id = 0
|
||||
fprintf(stderr, "0x%lx\n", trace[0]);
|
||||
// CHECK: [[FREE_FRAME_0:0x[0-9a-f]+]]
|
||||
fprintf(stderr, "0x%lx\n", trace[1]);
|
||||
// CHECK: [[FREE_FRAME_1:0x[0-9a-f]+]]
|
||||
|
||||
mem[0] = 'A'; // BOOM
|
||||
|
||||
// CHECK: ERROR: AddressSanitizer: heap-use-after-free
|
||||
// CHECK: WRITE of size 1 at 0x{{.*}}
|
||||
// CHECK: freed by thread T0 here:
|
||||
// CHECK: #0 [[FREE_FRAME_0]]
|
||||
// CHECK: #1 [[FREE_FRAME_1]]
|
||||
// CHECK: previously allocated by thread T0 here:
|
||||
// CHECK: #0 [[ALLOC_FRAME_0]]
|
||||
// CHECK: #1 [[ALLOC_FRAME_1]]
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue