123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- //+build amd64
- package sys_valgrind
- import "core: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)
- }
|