| /* | 
 |  * 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 <stdlib.h> | 
 |  | 
 | #include <cinttypes> | 
 |  | 
 | #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<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(*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<uint64_t>(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<uint64_t>(pointer)); | 
 |   void* addr = fn(pointer, size); | 
 |   AHeapProfile_reportAllocation(heap_id, reinterpret_cast<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(pointer)); | 
 |   void* addr = fn(pointer, nmemb, size); | 
 |   AHeapProfile_reportAllocation(heap_id, reinterpret_cast<uint64_t>(addr), | 
 |                                 nmemb * size); | 
 |   return addr; | 
 | } | 
 |  | 
 | }  // namespace profiling | 
 | }  // namespace perfetto |