• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <link.h>
17 #include <dlfcn.h>
18 #include <cstdlib>
19 
20 #include "mem_hooks.h"
21 #include "libpandabase/utils/span.h"
22 
23 namespace panda::os::unix::mem_hooks {
24 
25 size_t PandaHooks::allocViaStandard_ = 0;
26 bool PandaHooks::isActive_ = false;
27 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
28 PandaHooks::AddrRange PandaHooks::ignoreCodeRange_;
29 void *(*PandaHooks::realMalloc_)(size_t) = nullptr;
30 void *(*PandaHooks::realMemalign_)(size_t, size_t) = nullptr;
31 void (*PandaHooks::realFree_)(void *) = nullptr;
32 
FindLibDwarfCodeRegion(dl_phdr_info * info,size_t size,void * data)33 int FindLibDwarfCodeRegion(dl_phdr_info *info, [[maybe_unused]] size_t size, void *data)
34 {
35     auto arange = reinterpret_cast<PandaHooks::AddrRange *>(data);
36     if (std::string_view(info->dlpi_name).find("libdwarf.so") != std::string_view::npos) {
37         Span<const ElfW(Phdr)> phdrList(info->dlpi_phdr, info->dlpi_phnum);
38         for (ElfW(Phdr) phdr : phdrList) {
39             // NOLINTNEXTLINE(hicpp-signed-bitwise)
40             if (phdr.p_type == PT_LOAD && (phdr.p_flags & PF_X) != 0) {
41                 *arange = PandaHooks::AddrRange(info->dlpi_addr + phdr.p_vaddr, phdr.p_memsz);
42                 return 1;
43             }
44         }
45     }
46     return 0;
47 }
48 
49 /* static */
Initialize()50 void PandaHooks::Initialize()
51 {
52     // libdwarf allocates a lot of memory using malloc internally.
53     // Since this library is used only for debug purpose don't consider
54     // malloc calls from this library.
55     dl_iterate_phdr(FindLibDwarfCodeRegion, &PandaHooks::ignoreCodeRange_);
56 }
57 
58 /* static */
SaveRealFunctions()59 void PandaHooks::SaveRealFunctions()
60 {
61     realMalloc_ = reinterpret_cast<decltype(realMalloc_)>(
62         dlsym(RTLD_NEXT, "malloc"));  // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
63     ASSERT(realMalloc_ != nullptr);
64     realMemalign_ = reinterpret_cast<decltype(realMemalign_)>(
65         dlsym(RTLD_NEXT, "memalign"));  // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
66     ASSERT(realMemalign_ != nullptr);
67     realFree_ = reinterpret_cast<decltype(realFree_)>(
68         dlsym(RTLD_NEXT, "free"));  // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
69     ASSERT(realFree_ != nullptr);
70 }
71 
72 /* static */
ShouldCountAllocation(const void * caller)73 bool PandaHooks::ShouldCountAllocation(const void *caller)
74 {
75     return !ignoreCodeRange_.Contains(ToUintPtr(caller));
76 }
77 
78 /* static */
MallocHook(size_t size,const void * caller)79 void *PandaHooks::MallocHook(size_t size, const void *caller)
80 {
81     if (ShouldCountAllocation(caller)) {
82         allocViaStandard_ += size;
83     }
84     // tracking internal allocator is implemented by malloc, we would fail here with this option
85 #ifndef TRACK_INTERNAL_ALLOCATIONS
86     if (allocViaStandard_ > MAX_ALLOC_VIA_STANDARD) {
87         std::cerr << "Too many usage of standard allocations" << std::endl;
88         abort();
89     }
90 #endif                                 // TRACK_INTERNAL_ALLOCATIONS
91     void *result = realMalloc_(size);  // NOLINT(cppcoreguidelines-no-malloc)
92     if (UNLIKELY(result == nullptr)) {
93         std::cerr << "Malloc error" << std::endl;
94         abort();
95     }
96     return result;
97 }
98 
99 /* static */
MemalignHook(size_t alignment,size_t size,const void * caller)100 void *PandaHooks::MemalignHook(size_t alignment, size_t size, const void *caller)
101 {
102     if (ShouldCountAllocation(caller)) {
103         allocViaStandard_ += size;
104     }
105     // tracking internal allocator is implemented by malloc, we would fail here with this option
106 #ifndef TRACK_INTERNAL_ALLOCATIONS
107     if (allocViaStandard_ > MAX_ALLOC_VIA_STANDARD) {
108         std::cerr << "Too many usage of standard allocations" << std::endl;
109         abort();
110     }
111 #endif  // TRACK_INTERNAL_ALLOCATIONS
112     void *result = realMemalign_(alignment, size);
113     if (UNLIKELY(result == nullptr)) {
114         std::cerr << "Align error" << std::endl;
115         abort();
116     }
117     return result;
118 }
119 
120 /* static */
FreeHook(void * ptr,const void * caller)121 void PandaHooks::FreeHook(void *ptr, [[maybe_unused]] const void *caller)
122 {
123     realFree_(ptr);  // NOLINT(cppcoreguidelines-no-malloc)
124 }
125 
126 /* static */
Enable()127 void PandaHooks::Enable()
128 {
129 #ifdef PANDA_USE_MEMORY_HOOKS
130     isActive_ = true;
131 #endif  // PANDA_USE_MEMORY_HOOKS
132 }
133 
134 /* static */
Disable()135 void PandaHooks::Disable()
136 {
137 #ifdef PANDA_USE_MEMORY_HOOKS
138     isActive_ = false;
139 #endif  // PANDA_USE_MEMORY_HOOKS
140 }
141 
142 }  // namespace panda::os::unix::mem_hooks
143 
144 #ifdef PANDA_USE_MEMORY_HOOKS
145 
146 // NOLINTNEXTLINE(readability-redundant-declaration,readability-identifier-naming)
malloc(size_t size)147 void *malloc(size_t size) noexcept
148 {
149     if (panda::os::mem_hooks::PandaHooks::realMalloc_ == nullptr) {
150         panda::os::unix::mem_hooks::PandaHooks::SaveRealFunctions();
151     }
152     if (panda::os::mem_hooks::PandaHooks::IsActive()) {
153         void *caller = __builtin_return_address(0);
154         return panda::os::mem_hooks::PandaHooks::MallocHook(size, caller);
155     }
156     return panda::os::mem_hooks::PandaHooks::realMalloc_(size);
157 }
158 
159 // NOLINTNEXTLINE(readability-redundant-declaration,readability-identifier-naming)
memalign(size_t alignment,size_t size)160 void *memalign(size_t alignment, size_t size) noexcept
161 {
162     if (panda::os::mem_hooks::PandaHooks::realMemalign_ == nullptr) {
163         panda::os::unix::mem_hooks::PandaHooks::SaveRealFunctions();
164     }
165     if (panda::os::mem_hooks::PandaHooks::IsActive()) {
166         void *caller = __builtin_return_address(0);
167         return panda::os::mem_hooks::PandaHooks::MemalignHook(alignment, size, caller);
168     }
169     return panda::os::mem_hooks::PandaHooks::realMemalign_(alignment, size);
170 }
171 
172 // NOLINTNEXTLINE(readability-redundant-declaration,readability-identifier-naming)
free(void * ptr)173 void free(void *ptr) noexcept
174 {
175     if (panda::os::mem_hooks::PandaHooks::realFree_ == nullptr) {
176         panda::os::unix::mem_hooks::PandaHooks::SaveRealFunctions();
177     }
178     if (panda::os::mem_hooks::PandaHooks::IsActive()) {
179         void *caller = __builtin_return_address(0);
180         return panda::os::mem_hooks::PandaHooks::FreeHook(ptr, caller);
181     }
182     return panda::os::mem_hooks::PandaHooks::realFree_(ptr);
183 }
184 
185 #endif  // PANDA_USE_MEMORY_HOOKS
186