1 /**
2 * Copyright (c) 2021-2024 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 #include "include/tooling/debug_inf.h"
16
17 //
18 // Debuge interface for native tools(perf, libunwind).
19 //
20
21 namespace ark::tooling {
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25
26 enum CodeAction {
27 CODE_NOACTION = 0,
28 CODE_ADDED,
29 CODE_REMOVE,
30 };
31
32 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
33 struct PCodeItem {
34 std::atomic<PCodeItem *> next;
35 PCodeItem *prev;
36 const uint8_t *codeBase;
37 uint64_t codeSize;
38 uint64_t timestamp;
39 };
40
41 struct PCodeMetaInfo {
42 uint32_t version = 1;
43 uint32_t action = CODE_NOACTION;
44 PCodeItem *releventItem = nullptr;
45 std::atomic<PCodeItem *> head {nullptr};
46
47 // Panda-specific fields
48 uint32_t flags = 0;
49 uint32_t sizeMetaInfo = sizeof(PCodeMetaInfo);
50 uint32_t sizeCodeitem = sizeof(PCodeItem);
51 std::atomic_uint32_t updateLock {0};
52 uint64_t timestamp = 1;
53 };
54
55 // perf currently use g_jitDebugDescriptor and g_dexDebugDescriptor
56 // to find the jit code item and dexfiles.
57 // for using the variable interface, we doesn't change the name in panda
58 // NOLINTNEXTLINE(readability-identifier-naming, fuchsia-statically-constructed-objects)
59 PCodeMetaInfo g_jitDebugDescriptor;
60 // NOLINTNEXTLINE(readability-identifier-naming, fuchsia-statically-constructed-objects)
61 PCodeMetaInfo g_dexDebugDescriptor;
62
63 #ifdef __cplusplus
64 } // extern "C"
65 #endif
66
67 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
68 std::map<const std::string, PCodeItem *> DebugInf::aexItemMap_;
69 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
70 ark::os::memory::Mutex DebugInf::jitItemLock_;
71 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
72 ark::os::memory::Mutex DebugInf::aexItemLock_;
73
AddCodeMetaInfo(const panda_file::File * file)74 void DebugInf::AddCodeMetaInfo(const panda_file::File *file)
75 {
76 ark::os::memory::LockHolder lock(aexItemLock_);
77 ASSERT(file != nullptr);
78 auto it = aexItemMap_.find(file->GetFilename());
79 if (it != aexItemMap_.end()) {
80 return;
81 }
82
83 PCodeItem *item = AddCodeMetaInfoImpl(&g_dexDebugDescriptor, {file->GetBase(), file->GetHeader()->fileSize});
84 aexItemMap_.emplace(file->GetFilename(), item);
85 }
86
DelCodeMetaInfo(const panda_file::File * file)87 void DebugInf::DelCodeMetaInfo(const panda_file::File *file)
88 {
89 ark::os::memory::LockHolder lock(aexItemLock_);
90 ASSERT(file != nullptr);
91 auto it = aexItemMap_.find(file->GetFilename());
92 if (it == aexItemMap_.end()) {
93 return;
94 }
95
96 DelCodeMetaInfoImpl(&g_dexDebugDescriptor, file);
97 }
98
Lock(PCodeMetaInfo * mi)99 void DebugInf::Lock(PCodeMetaInfo *mi)
100 {
101 // Atomic with relaxed order reason: data race with update_lock_ with no synchronization or ordering constraints
102 // imposed on other reads or writes
103 mi->updateLock.fetch_add(1, std::memory_order_relaxed);
104 std::atomic_thread_fence(std::memory_order_release);
105 }
106
UnLock(PCodeMetaInfo * mi)107 void DebugInf::UnLock(PCodeMetaInfo *mi)
108 {
109 std::atomic_thread_fence(std::memory_order_release);
110 // Atomic with relaxed order reason: data race with update_lock_ with no synchronization or ordering constraints
111 // imposed on other reads or writes
112 mi->updateLock.fetch_add(1, std::memory_order_relaxed);
113 }
114
AddCodeMetaInfoImpl(PCodeMetaInfo * metaInfo,Span<const uint8_t> inss)115 PCodeItem *DebugInf::AddCodeMetaInfoImpl(PCodeMetaInfo *metaInfo, [[maybe_unused]] Span<const uint8_t> inss)
116 {
117 uint64_t timestamp = std::max(metaInfo->timestamp + 1, ark::time::GetCurrentTimeInNanos());
118
119 // Atomic with relaxed order reason: data race with metaInfo with no synchronization or ordering constraints imposed
120 // on other reads or writes
121 auto *head = metaInfo->head.load(std::memory_order_relaxed);
122
123 auto *codeItem = new PCodeItem;
124 codeItem->codeBase = inss.begin();
125 codeItem->codeSize = inss.Size();
126 codeItem->prev = nullptr;
127 // Atomic with relaxed order reason: data race with code_item with no synchronization or ordering constraints
128 // imposed on other reads or writes
129 codeItem->next.store(head, std::memory_order_relaxed);
130 codeItem->timestamp = timestamp;
131
132 // lock
133 Lock(metaInfo);
134 if (head != nullptr) {
135 head->prev = codeItem;
136 }
137
138 // Atomic with relaxed order reason: data race with metaInfo with no synchronization or ordering constraints imposed
139 // on other reads or writes
140 metaInfo->head.store(codeItem, std::memory_order_relaxed);
141 metaInfo->releventItem = codeItem;
142 metaInfo->action = CODE_ADDED;
143
144 // unlock
145 UnLock(metaInfo);
146
147 return codeItem;
148 }
149
DelCodeMetaInfoImpl(PCodeMetaInfo * metaInfo,const panda_file::File * file)150 void DebugInf::DelCodeMetaInfoImpl(PCodeMetaInfo *metaInfo, const panda_file::File *file)
151 {
152 PCodeItem *codeItem = aexItemMap_[file->GetFilename()];
153 ASSERT(codeItem != nullptr);
154 uint64_t timestamp = std::max(metaInfo->timestamp + 1, ark::time::GetCurrentTimeInNanos());
155 // lock
156 Lock(metaInfo);
157
158 // Atomic with relaxed order reason: data race with code_item with no synchronization or ordering constraints
159 // imposed on other reads or writes
160 auto next = codeItem->next.load(std::memory_order_relaxed);
161 if (codeItem->prev != nullptr) {
162 // Atomic with relaxed order reason: data race with code_item with no synchronization or ordering constraints
163 // imposed on other reads or writes
164 codeItem->prev->next.store(next, std::memory_order_relaxed);
165 } else {
166 // Atomic with relaxed order reason: data race with metaInfo with no synchronization or ordering constraints
167 // imposed on other reads or writes
168 metaInfo->head.store(next, std::memory_order_relaxed);
169 }
170
171 if (next != nullptr) {
172 next->prev = codeItem->prev;
173 }
174
175 metaInfo->releventItem = codeItem;
176 metaInfo->action = CODE_REMOVE;
177 metaInfo->timestamp = timestamp;
178
179 // unlock
180 UnLock(metaInfo);
181 }
182 } // namespace ark::tooling
183