• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 
16 #include "ecmascript/dfx/hprof/rawheap_translate/metadata_parse.h"
17 
18 namespace rawheap_translate {
Parse(const cJSON * object)19 bool Meta::Parse(const cJSON *object)
20 {
21     return ParseVersion(object) &&
22            ParseTypeEnums(object) &&
23            ParseTypeList(object) &&
24            ParseTypeLayout(object) &&
25            SetObjTypeBitFieldOffset() &&
26            SetNativatePointerBindingSizeOffset();
27 }
28 
GetNativateSize(char * obj,char * hclass)29 uint32_t Meta::GetNativateSize(char *obj, char *hclass)
30 {
31     JSType typeId = GetObjTypeFromHClass(hclass);
32     if (typeId != GetObjTypeFromTypeName("JS_NATIVE_POINTER")) {
33         return 0;
34     }
35     return ByteToU32(obj + nativatePointerBindingSizeOffset_);
36 }
37 
GetTypeNameFromHClass(char * hclass)38 std::string Meta::GetTypeNameFromHClass(char *hclass)
39 {
40     JSType typeId = GetObjTypeFromHClass(hclass);
41     if (typeId < enumsVec_.size()) {
42         return enumsVec_[typeId];
43     }
44     LOG_ERROR("Meta::GetTypeNameFromTypeId: typeId out of range, typeId=" + std::to_string(typeId));
45     return "UNKNOWN_TYPE";
46 }
47 
GetObjectLayout(const std::string & name)48 std::shared_ptr<Layout> Meta::GetObjectLayout(const std::string &name)
49 {
50     auto layout = layout_.find(name);
51     if (layout != layout_.end()) {
52         return layout->second;
53     }
54     return nullptr;
55 }
56 
IsString(char * hclass)57 bool Meta::IsString(char *hclass)
58 {
59     JSType typeId = GetObjTypeFromHClass(hclass);
60     JSType stringFirst = GetObjTypeFromTypeName(GetTypeDesc("string_first"));
61     JSType stringLast = GetObjTypeFromTypeName(GetTypeDesc("string_last"));
62     if (stringFirst <= typeId && typeId <= stringLast) {
63         return true;
64     }
65     return false;
66 }
67 
IsDictionaryMode(char * hclass)68 bool Meta::IsDictionaryMode(char *hclass)
69 {
70     return GetObjTypeFromHClass(hclass) == GetObjTypeFromTypeName("TAGGED_DICTIONARY");
71 }
72 
IsJSObject(char * hclass)73 bool Meta::IsJSObject(char *hclass)
74 {
75     JSType typeId = GetObjTypeFromHClass(hclass);
76     JSType stringFirst = GetObjTypeFromTypeName(GetTypeDesc("js_object_first"));
77     JSType stringLast = GetObjTypeFromTypeName(GetTypeDesc("js_object_last"));
78     if (stringFirst <= typeId && typeId <= stringLast) {
79         return true;
80     }
81     return false;
82 }
83 
IsGlobalEnv(char * hclass)84 bool Meta::IsGlobalEnv(char *hclass)
85 {
86     return GetObjTypeFromHClass(hclass) == GetObjTypeFromTypeName("GLOBAL_ENV");
87 }
88 
GetNodeTypeFromHClass(char * hclass)89 NodeType Meta::GetNodeTypeFromHClass(char *hclass)
90 {
91     std::string name = GetTypeNameFromHClass(hclass);
92     auto type = enumsMapNodeType_.find(name);
93     if (type != enumsMapNodeType_.end()) {
94         return type->second;
95     }
96     return DEFAULT_NODETYPE;  // 8: means DEFAULT node type
97 }
98 
VisitObjectBody(const std::string & name,const ObjRangeVisitor & visitor,uint32_t & baseOffset)99 void Meta::VisitObjectBody(const std::string &name, const ObjRangeVisitor &visitor, uint32_t &baseOffset)
100 {
101     auto metadata = GetMetaData(name);
102     if (!metadata) {
103         return;
104     }
105 
106     for (const auto &parent : metadata->parents) {
107         VisitObjectBody(parent, visitor, baseOffset);
108     }
109 
110     visitor(metadata, baseOffset);
111     baseOffset += metadata->endOffset;
112 }
113 
SetObjTypeBitFieldOffset()114 bool Meta::SetObjTypeBitFieldOffset()
115 {
116     auto visitor = [this] (std::shared_ptr<MetaData> &metadata, uint32_t offset) {
117         for (const auto &field : metadata->fields) {
118             if (field->name == "BitField") {
119                 objTypeBitFieldOffset_ = offset + field->offset;
120                 objTypeBitFieldSize_ = field->size;
121             }
122         }
123     };
124     uint32_t baseOffset = 0;
125     VisitObjectBody("HCLASS", visitor, baseOffset);
126     LOG_INFO("Meta::SetObjTypeBitFieldOffset: offset=" + std::to_string(objTypeBitFieldOffset_));
127     return true;
128 }
129 
SetNativatePointerBindingSizeOffset()130 bool Meta::SetNativatePointerBindingSizeOffset()
131 {
132     auto visitor = [this] (std::shared_ptr<MetaData> &metadata, uint32_t offset) {
133         for (const auto &field : metadata->fields) {
134             if (field->name == "BindingSize") {
135                 nativatePointerBindingSizeOffset_ = offset + field->offset;
136                 nativatePointerBindingSize_ = field->size;
137             }
138         }
139     };
140     uint32_t baseOffset = 0;
141     VisitObjectBody("JS_NATIVE_POINTER", visitor, baseOffset);
142     LOG_INFO("Meta::SetNativatePointerBindingSizeOffset: offset=" + std::to_string(nativatePointerBindingSizeOffset_));
143     return true;
144 }
145 
GetObjTypeFromHClass(char * hclass)146 JSType Meta::GetObjTypeFromHClass(char *hclass)
147 {
148     return ByteToU32(hclass + objTypeBitFieldOffset_) & 0xFF;  // lower 8-bits of 32-bit value means JSType
149 }
150 
GetObjTypeFromTypeName(const std::string & name)151 JSType Meta::GetObjTypeFromTypeName(const std::string &name)
152 {
153     auto typeEnum = enumsMapJSType_.find(name);
154     if (typeEnum == enumsMapJSType_.end()) {
155         return 0;
156     }
157     return typeEnum->second;
158 }
159 
GetTypeDesc(const std::string & name)160 std::string Meta::GetTypeDesc(const std::string &name)
161 {
162     auto result = typeDesc_.find(name);
163     if (result != typeDesc_.end()) {
164         return result->second;
165     }
166     return "UNKNOWN_TYPE";
167 }
168 
ParseTypeEnums(const cJSON * json)169 bool Meta::ParseTypeEnums(const cJSON *json)
170 {
171     cJSON *typeEnums = cJSON_GetObjectItem(json, "type_enum");
172     auto visit = [&typeEnums, this] (const cJSON *item, int index) {
173         std::string name = item->string;
174         uint32_t edgeType = 0;
175         if (GetUInt32(typeEnums, name.c_str(), edgeType)) {
176             enumsVec_.push_back(name);
177             enumsMapJSType_.emplace(name, static_cast<JSType>(index));
178             enumsMapNodeType_.emplace(name, static_cast<uint8_t>(edgeType));
179         }
180     };
181     IterateJSONArray(typeEnums, visit);
182     LOG_INFO("Meta::ParseTypeEnums: parse type enums, size=" + std::to_string(enumsVec_.size()));
183     return true;
184 }
185 
ParseTypeList(const cJSON * json)186 bool Meta::ParseTypeList(const cJSON *json)
187 {
188     cJSON *metadatas {nullptr};
189     std::vector<std::string> *curParents {nullptr};
190     std::vector<std::shared_ptr<Field>> *curField {nullptr};
191     if (!GetArray(json, "type_list", &metadatas)) {
192         LOG_ERROR("Meta::ParseTypeList: type list parse failed!");
193         return false;
194     }
195 
196     auto parentVisitor = [&curParents] (const cJSON *item, [[maybe_unused]] int index) {
197         std::string value {};
198         if (GetString(item, value)) {
199             curParents->push_back(value);
200         }
201     };
202 
203     auto offsetVisitor = [&curField] (const cJSON *item, [[maybe_unused]] int index) {
204         auto field = std::make_shared<Field>();
205         if (GetUInt32(item, "offset", field->offset) &&
206             GetString(item, "name", field->name) &&
207             GetUInt32(item, "size", field->size)) {
208             curField->push_back(field);
209         }
210     };
211 
212     auto metaVisitor =
213         [&curParents, &curField, &parentVisitor, &offsetVisitor, this] (const cJSON *item, [[maybe_unused]] int index) {
214         cJSON *fields {nullptr};
215         cJSON *parents {nullptr};
216         if (!GetArray(item, "offsets", &fields) || !GetArray(item, "parents", &parents)) {
217             return;
218         }
219 
220         auto metadata = std::make_shared<MetaData>();
221         curParents = &metadata->parents;
222         curField = &metadata->fields;
223         IterateJSONArray(fields, offsetVisitor);
224         IterateJSONArray(parents, parentVisitor);
225 
226         if (GetString(item, "name", metadata->name) && GetUInt32(item, "end_offset", metadata->endOffset)) {
227             metadata_.emplace(metadata->name, metadata);
228         }
229 
230         GetString(item, "visit_type", metadata->visitType);
231     };
232 
233     IterateJSONArray(metadatas, metaVisitor);
234     LOG_INFO("Meta::ParseTypeList: parse type list, obj size = " + std::to_string(metadata_.size()));
235     return true;
236 }
237 
ParseTypeLayout(const cJSON * json)238 bool Meta::ParseTypeLayout(const cJSON *json)
239 {
240     cJSON *object = cJSON_GetObjectItem(json, "type_layout");
241 
242     cJSON *dictLayout = cJSON_GetObjectItem(object, "Dictionary_layout");
243     auto layout = std::make_shared<Layout>();
244     GetString(dictLayout, "name", layout->name);
245     GetUInt32(dictLayout, "key_index", layout->keyIndex);
246     GetUInt32(dictLayout, "value_index", layout->valueIndex);
247     GetUInt32(dictLayout, "detail_index", layout->detailIndex);
248     GetUInt32(dictLayout, "entry_size", layout->entrySize);
249     GetUInt32(dictLayout, "header_size", layout->headerSize);
250     layout_.emplace(layout->name, layout);
251     LOG_INFO("Meta::ParseTypeLayout: parse type layout, size=" + std::to_string(layout_.size()));
252 
253     cJSON *typeRange = cJSON_GetObjectItem(object, "Type_range");
254     auto visit = [&typeRange, this] (const cJSON *item, [[maybe_unused]] int index) {
255         std::string key = item->string;
256         std::string value {};
257         if (GetString(typeRange, key.c_str(), value)) {
258             typeDesc_.emplace(key, value);
259         }
260     };
261     IterateJSONArray(typeRange, visit);
262     LOG_INFO("Meta::ParseTypeLayout: parse type desc, size=" + std::to_string(typeDesc_.size()));
263     return true;
264 }
265 
ParseVersion(const cJSON * json)266 bool Meta::ParseVersion(const cJSON *json)
267 {
268     std::string version {};
269     if (!GetString(json, "version", version)) {
270         LOG_ERROR("Meta::ParseVersion: version not found!");
271         return false;
272     }
273 
274     if (!CheckVersion(version)) {
275         return false;
276     }
277 
278     LOG_INFO("Meta::ParseVersion: current metadata version is " + version);
279     return true;
280 }
GetMetaData(const std::string & name)281 std::shared_ptr<MetaData> Meta::GetMetaData(const std::string &name)
282 {
283     auto metadata = metadata_.find(name);
284     if (metadata != metadata_.end()) {
285         return metadata->second;
286     }
287     return nullptr;
288 }
289 
IterateJSONArray(const cJSON * array,const std::function<void (const cJSON *,int)> & visitor)290 void Meta::IterateJSONArray(const cJSON *array, const std::function<void(const cJSON *, int)> &visitor)
291 {
292     int size = cJSON_GetArraySize(array);
293     for (int i = 0; i < size; i++) {
294         cJSON *item = cJSON_GetArrayItem(array, i);
295         visitor(item, i);
296     }
297 }
298 
GetArray(const cJSON * json,const char * key,cJSON ** value)299 bool Meta::GetArray(const cJSON *json, const char *key, cJSON **value)
300 {
301     cJSON *array = cJSON_GetObjectItem(json, key);
302     if (array == nullptr || cJSON_IsArray(array) == 0) {
303         return false;
304     }
305     *value = array;
306     return true;
307 }
308 
GetString(const cJSON * json,const char * key,std::string & value)309 bool Meta::GetString(const cJSON *json, const char *key, std::string &value)
310 {
311     cJSON *item = cJSON_GetObjectItem(json, key);
312     if (item == nullptr) {
313         return false;
314     }
315     return GetString(item, value);
316 }
317 
GetString(const cJSON * json,std::string & value)318 bool Meta::GetString(const cJSON *json, std::string &value)
319 {
320     if (cJSON_IsString(json) == 0) {
321         return false;
322     }
323     value = json->valuestring;
324     return true;
325 }
326 
GetUInt32(const cJSON * json,const char * key,uint32_t & value)327 bool Meta::GetUInt32(const cJSON *json, const char *key, uint32_t &value)
328 {
329     cJSON *item = cJSON_GetObjectItem(json, key);
330     if (item == nullptr) {
331         return false;
332     }
333     return GetUInt32(item, value);
334 }
335 
GetUInt32(const cJSON * json,uint32_t & value)336 bool Meta::GetUInt32(const cJSON *json, uint32_t &value)
337 {
338     if (cJSON_IsNumber(json) == 0) {
339         return false;
340     }
341     if (json->valuedouble < 0 || json->valuedouble > static_cast<double>(UINT32_MAX)) {
342         return false;
343     }
344     value = static_cast<uint32_t>(json->valuedouble);
345     return true;
346 }
347 }  // namespace rawheap_translate