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