/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "perfetto/ext/base/utils.h" #include "perfetto/heap_profile.h" #include "src/profiling/memory/wrap_allocators.h" namespace perfetto { namespace profiling { namespace { size_t RoundUpToSysPageSize(size_t req_size) { const size_t page_size = base::GetSysPageSize(); return (req_size + page_size - 1) & ~(page_size - 1); } } // namespace void* wrap_malloc(uint32_t heap_id, void* (*fn)(size_t), size_t size) { void* addr = fn(size); AHeapProfile_reportAllocation(heap_id, reinterpret_cast(addr), size); return addr; } void* wrap_calloc(uint32_t heap_id, void* (*fn)(size_t, size_t), size_t nmemb, size_t size) { void* addr = fn(nmemb, size); AHeapProfile_reportAllocation(heap_id, reinterpret_cast(addr), nmemb * size); return addr; } void* wrap_memalign(uint32_t heap_id, void* (*fn)(size_t, size_t), size_t alignment, size_t size) { void* addr = fn(alignment, size); AHeapProfile_reportAllocation(heap_id, reinterpret_cast(addr), size); return addr; } int wrap_posix_memalign(uint32_t heap_id, int (*fn)(void**, size_t, size_t), void** memptr, size_t alignment, size_t size) { int res = fn(memptr, alignment, size); if (res != 0) return res; AHeapProfile_reportAllocation(heap_id, reinterpret_cast(*memptr), size); return 0; } // Note: we record the free before calling the backing implementation to make // sure that the address is not reused before we've processed the deallocation // (which includes assigning a sequence id to it). void wrap_free(uint32_t heap_id, void (*fn)(void*), void* pointer) { // free on a nullptr is valid but has no effect. Short circuit here, for // various advantages: // * More efficient // * Notably printf calls free(nullptr) even when it is used in a way // malloc-free way, as it unconditionally frees the pointer even if // it was never written to. // Short circuiting here makes it less likely to accidentally build // infinite recursion. if (pointer == nullptr) return; AHeapProfile_reportFree(heap_id, reinterpret_cast(pointer)); return fn(pointer); } // As with the free, we record the deallocation before calling the backing // implementation to make sure the address is still exclusive while we're // processing it. void* wrap_realloc(uint32_t heap_id, void* (*fn)(void*, size_t), void* pointer, size_t size) { if (pointer) AHeapProfile_reportFree(heap_id, reinterpret_cast(pointer)); void* addr = fn(pointer, size); AHeapProfile_reportAllocation(heap_id, reinterpret_cast(addr), size); return addr; } void* wrap_pvalloc(uint32_t heap_id, void* (*fn)(size_t), size_t size) { void* addr = fn(size); AHeapProfile_reportAllocation(heap_id, reinterpret_cast(addr), RoundUpToSysPageSize(size)); return addr; } void* wrap_valloc(uint32_t heap_id, void* (*fn)(size_t), size_t size) { void* addr = fn(size); AHeapProfile_reportAllocation(heap_id, reinterpret_cast(addr), size); return addr; } void* wrap_reallocarray(uint32_t heap_id, void* (*fn)(void*, size_t, size_t), void* pointer, size_t nmemb, size_t size) { if (pointer) AHeapProfile_reportFree(heap_id, reinterpret_cast(pointer)); void* addr = fn(pointer, nmemb, size); AHeapProfile_reportAllocation(heap_id, reinterpret_cast(addr), nmemb * size); return addr; } } // namespace profiling } // namespace perfetto