mirror of
https://github.com/odin-lang/Odin.git
synced 2025-12-29 17:34:34 +00:00
169 lines
7.1 KiB
Odin
169 lines
7.1 KiB
Odin
//+build amd64
|
|
package sys_valgrind
|
|
|
|
import "base:intrinsics"
|
|
|
|
Mem_Check_Client_Request :: enum uintptr {
|
|
Make_Mem_No_Access = 'M'<<24 | 'C'<<16,
|
|
Make_Mem_Undefined,
|
|
Make_Mem_Defined,
|
|
Discard,
|
|
Check_Mem_Is_Addressable,
|
|
Check_Mem_Is_Defined,
|
|
Do_Leak_Check,
|
|
Count_Leaks,
|
|
Get_Vbits,
|
|
Set_Vbits,
|
|
Create_Block,
|
|
Make_Mem_Defined_If_Addressable,
|
|
Count_Leak_Blocks,
|
|
Enable_Addr_Error_Reporting_In_Range,
|
|
Disable_Addr_Error_Reporting_In_Range,
|
|
}
|
|
|
|
@(require_results)
|
|
mem_check_client_request_expr :: #force_inline proc "c" (default: uintptr, request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
|
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
|
|
}
|
|
mem_check_client_request_stmt :: #force_inline proc "c" (request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
|
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
|
|
}
|
|
|
|
// Mark memory at `raw_data(qzz)` as unaddressable for `len(qzz)` bytes.
|
|
// Returns true when run on Valgrind and false otherwise.
|
|
make_mem_no_access :: proc "c" (qzz: []byte) -> bool {
|
|
return 0 != mem_check_client_request_expr(0, .Make_Mem_No_Access, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
|
|
}
|
|
// Mark memory at `raw_data(qzz)` as addressable but undefined for `len(qzz)` bytes.
|
|
// Returns true when run on Valgrind and false otherwise.
|
|
make_mem_undefined :: proc "c" (qzz: []byte) -> bool {
|
|
return 0 != mem_check_client_request_expr(0, .Make_Mem_Undefined, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
|
|
}
|
|
// Mark memory at `raw_data(qzz)` as addressable for `len(qzz)` bytes.
|
|
// Returns true when run on Valgrind and false otherwise.
|
|
make_mem_defined :: proc "c" (qzz: []byte) -> bool {
|
|
return 0 != mem_check_client_request_expr(0, .Make_Mem_Defined, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
|
|
}
|
|
|
|
// Check that memory at `raw_data(qzz)` is addressable for `len(qzz)` bytes.
|
|
// If suitable addressibility is not established, Valgrind prints an error
|
|
// message and returns the address of the first offending byte.
|
|
// Otherwise it returns zero.
|
|
check_mem_is_addressable :: proc "c" (qzz: []byte) -> uintptr {
|
|
return mem_check_client_request_expr(0, .Check_Mem_Is_Addressable, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
|
|
}
|
|
// Check that memory at `raw_data(qzz)` is addressable and defined for `len(qzz)` bytes.
|
|
// If suitable addressibility and definedness are not established,
|
|
// Valgrind prints an error message and returns the address of the first
|
|
// offending byte. Otherwise it returns zero.
|
|
check_mem_is_defined :: proc "c" (qzz: []byte) -> uintptr {
|
|
return mem_check_client_request_expr(0, .Check_Mem_Is_Defined, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
|
|
}
|
|
|
|
// Similar to `make_mem_defined(qzz)` except that addressability is not altered:
|
|
// bytes which are addressable are marked as defined, but those which
|
|
// are not addressable are left unchanged.
|
|
// Returns true when run on Valgrind and false otherwise.
|
|
make_mem_defined_if_addressable :: proc "c" (qzz: []byte) -> bool {
|
|
return 0 != mem_check_client_request_expr(0, .Make_Mem_Defined_If_Addressable, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
|
|
}
|
|
|
|
// Create a block-description handle.
|
|
// The description is an ascii string which is included in any messages
|
|
// pertaining to addresses within the specified memory range.
|
|
// Has no other effect on the properties of the memory range.
|
|
create_block :: proc "c" (qzz: []u8, desc: cstring) -> bool {
|
|
return 0 != mem_check_client_request_expr(0, .Create_Block, uintptr(raw_data(qzz)), uintptr(len(qzz)), uintptr(rawptr(desc)), 0, 0)
|
|
}
|
|
// Discard a block-description-handle. Returns true for an invalid handle, false for a valid handle.
|
|
discard :: proc "c" (blk_index: uintptr) -> bool {
|
|
return 0 != mem_check_client_request_expr(0, .Discard, 0, blk_index, 0, 0, 0)
|
|
}
|
|
|
|
|
|
// Do a full memory leak check (like `--leak-check=full`) mid-execution.
|
|
leak_check :: proc "c" () {
|
|
mem_check_client_request_stmt(.Do_Leak_Check, 0, 0, 0, 0, 0)
|
|
}
|
|
// Same as `leak_check()` but only showing the entries for which there was an increase
|
|
// in leaked bytes or leaked nr of blocks since the previous leak search.
|
|
added_leak_check :: proc "c" () {
|
|
mem_check_client_request_stmt(.Do_Leak_Check, 0, 1, 0, 0, 0)
|
|
}
|
|
// Same as `added_leak_check()` but showing entries with increased or decreased
|
|
// leaked bytes/blocks since previous leak search.
|
|
changed_leak_check :: proc "c" () {
|
|
mem_check_client_request_stmt(.Do_Leak_Check, 0, 2, 0, 0, 0)
|
|
}
|
|
// Do a summary memory leak check (like `--leak-check=summary`) mid-execution.
|
|
quick_leak_check :: proc "c" () {
|
|
mem_check_client_request_stmt(.Do_Leak_Check, 1, 0, 0, 0, 0)
|
|
}
|
|
|
|
Count_Result :: struct {
|
|
leaked: uint,
|
|
dubious: uint,
|
|
reachable: uint,
|
|
suppressed: uint,
|
|
}
|
|
|
|
count_leaks :: proc "c" () -> (res: Count_Result) {
|
|
mem_check_client_request_stmt(
|
|
.Count_Leaks,
|
|
uintptr(&res.leaked),
|
|
uintptr(&res.dubious),
|
|
uintptr(&res.reachable),
|
|
uintptr(&res.suppressed),
|
|
0,
|
|
)
|
|
return
|
|
}
|
|
|
|
count_leak_blocks :: proc "c" () -> (res: Count_Result) {
|
|
mem_check_client_request_stmt(
|
|
.Count_Leak_Blocks,
|
|
uintptr(&res.leaked),
|
|
uintptr(&res.dubious),
|
|
uintptr(&res.reachable),
|
|
uintptr(&res.suppressed),
|
|
0,
|
|
)
|
|
return
|
|
}
|
|
|
|
// Get the validity data for addresses zza and copy it
|
|
// into the provided zzvbits array. Return values:
|
|
// 0 - if not running on valgrind
|
|
// 1 - success
|
|
// 2 - [previously indicated unaligned arrays; these are now allowed]
|
|
// 3 - if any parts of zzsrc/zzvbits are not addressable.
|
|
// The metadata is not copied in cases 0, 2 or 3 so it should be
|
|
// impossible to segfault your system by using this call.
|
|
get_vbits :: proc(zza, zzvbits: []byte) -> u8 {
|
|
// assert requires a `context` thus these procedures cannot `proc "c"`
|
|
assert(len(zzvbits) >= len(zza)/8)
|
|
return u8(mem_check_client_request_expr(0, .Get_Vbits, uintptr(raw_data(zza)), uintptr(raw_data(zzvbits)), uintptr(len(zza)), 0, 0))
|
|
}
|
|
|
|
// Set the validity data for addresses zza, copying it
|
|
// from the provided zzvbits array. Return values:
|
|
// 0 - if not running on valgrind
|
|
// 1 - success
|
|
// 2 - [previously indicated unaligned arrays; these are now allowed]
|
|
// 3 - if any parts of zza/zzvbits are not addressable.
|
|
// The metadata is not copied in cases 0, 2 or 3 so it should be
|
|
// impossible to segfault your system by using this call.
|
|
set_vbits :: proc(zzvbits, zza: []byte) -> u8 {
|
|
// assert requires a `context` thus these procedures cannot `proc "c"`
|
|
assert(len(zzvbits) >= len(zza)/8)
|
|
return u8(mem_check_client_request_expr(0, .Set_Vbits, uintptr(raw_data(zza)), uintptr(raw_data(zzvbits)), uintptr(len(zza)), 0, 0))
|
|
}
|
|
|
|
// (Re-)enable reporting of addressing errors in the specified address range.
|
|
enable_addr_error_reporting_in_range :: proc "c" (qzz: []byte) -> uintptr {
|
|
return mem_check_client_request_expr(0, .Enable_Addr_Error_Reporting_In_Range, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
|
|
}
|
|
// Disable reporting of addressing errors in the specified address range.
|
|
disable_addr_error_reporting_in_range :: proc "c" (qzz: []byte) -> uintptr {
|
|
return mem_check_client_request_expr(0, .Disable_Addr_Error_Reporting_In_Range, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
|
|
} |