Proposal: ASan debugging API

Hi,

I would like to improve the debugging experience for ASan. The idea is to have a couple of useful commands in LLDB (probably implemented as Python scripts) that could help the user when they are debugging an ASan-enabled binary. We already have some debugging API (asan_interface.h):

// Print the description of addr (useful when debugging in gdb).
void __asan_describe_address(void *addr);

What I’d like to have is a few more API on the ASan/compiler-rt side to query various information that ASan can provide, both about an error report and about general addresses, something like:

// Useful for calling from a debugger to get information about an error.
// If an error has been (or is beign) reported, returns the pc, bp, sp,
// address, access type, access type and bug description, and the return
// value of the function is 1. If no error occurred yet, returns 0.
int __asan_get_report_data(void **pc, void **bp, void **sp, void **addr,
int *is_write, size_t *access_size,
char **bug_description);

// Address/memory type from ASan’s point of view.
typedef enum {
__ADDRESS_TYPE_UNKNOWN,
__ADDRESS_TYPE_SHADOW_LOW,
__ADDRESS_TYPE_SHADOW_GAP,
__ADDRESS_TYPE_SHADOW_HIGH,
__ADDRESS_TYPE_GLOBAL,
__ADDRESS_TYPE_STACK,
__ADDRESS_TYPE_HEAP,
} asan_address_type;

// Useful for calling from the debugger to get information about a pointer.
// Return one of the _ADDRESS_TYPE* enum values. If global or stack, tries
// to also return the variable name, address and size. If heap, tries to
// return the chunk address and size.
int __asan_get_address_type(void *addr, char **region_name,
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. Returns 1 on success, 0 on error.
int __asan_get_alloc_stack(void *addr, void **trace, size_t *frame_count,
void **top_frame_bp, int *thread_id);

// Useful for calling from the debugger to get the free stack trace
// and thread ID for a heap address. Returns 1 on success, 0 on error.
int __asan_get_free_stack(void *addr, void **trace, size_t *frame_count,
void **top_frame_bp, 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);

Hi,

I would like to improve the debugging experience for ASan. The idea is to have a couple of useful commands in LLDB (probably implemented as Python scripts) that could help the user when they are debugging an ASan-enabled binary. We already have some debugging API (asan_interface.h):

// Print the description of addr (useful when debugging in gdb).
void __asan_describe_address(void *addr);

What I’d like to have is a few more API to query various information that ASan can provide, both about an error report and about general addresses, something like:

// Useful for calling from a debugger to get information about an error.
// If an error has been (or is being) reported, returns the pc, bp, sp,
// address, access type, access type and bug description, and the return
// value of the function is 1. If no error occurred yet, returns 0.
int __asan_get_report_data(void **pc, void **bp, void **sp, void **addr,
int *is_write, size_t *access_size,
char **bug_description);

// Address/memory type from ASan’s point of view.
typedef enum {
__ADDRESS_TYPE_UNKNOWN,
__ADDRESS_TYPE_SHADOW_LOW,
__ADDRESS_TYPE_SHADOW_GAP,
__ADDRESS_TYPE_SHADOW_HIGH,
__ADDRESS_TYPE_GLOBAL,
__ADDRESS_TYPE_STACK,
__ADDRESS_TYPE_HEAP,
} asan_address_type;

// Useful for calling from the debugger to get information about a pointer.
// Return one of the _ADDRESS_TYPE* enum values. If global or stack, tries
// to also return the variable name, address and size. If heap, tries to
// return the chunk address and size.
int __asan_get_address_type(void *addr, char **region_name,
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. Returns 1 on success, 0 on error.
int __asan_get_alloc_stack(void *addr, void **trace, size_t *frame_count,
void **top_frame_bp, int *thread_id);

// Useful for calling from the debugger to get the free stack trace
// and thread ID for a heap address. Returns 1 on success, 0 on error.
int __asan_get_free_stack(void *addr, void **trace, size_t *frame_count,
void **top_frame_bp, 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);

The information that this API would provide is currently only available in the textual form in ASan reports. Having an API to provide it would enable implementation of various tools/script for LLDB and GDB.

Kuba

Should probably involve the LLDB developers as well here.

I can't really comment on what ASAN knows and can tell the user, or whether these API's represent that well. These would be easy enough to call from the debugger, that's no problem.

The main warning from our side is to remember that since you are reporting memory state, you will most likely not want to let the whole program run while you are gathering this data. So you have to be pretty careful about how you write these functions. Don't for instance call malloc, that is quite likely to deadlock against other threads, etc... But we already gave Kuba an earful about this, so I'm not sure reiterating this here is necessary.

Jim

The overall idea makes sense, especially if there is a real interest from gdb/lldb users.
So far __asan_describe_address was the only thing that anyone requested, but we could be proactive too.
Please send patches as usual, with tests (compiler-rt/test/asan/TestCases), and preferably in small chunks.

–kcc