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 <chrono>
17 #include "ecmascript/dfx/hprof/rawheap_translate/rawheap_translate.h"
18 #include "ecmascript/dfx/hprof/rawheap_translate/serializer.h"
19
20 namespace rawheap_translate {
~RawHeap()21 RawHeap::~RawHeap()
22 {
23 delete strTable_;
24 nodes_.clear();
25 edges_.clear();
26 }
27
TranslateRawheap(const std::string & inputPath,const std::string & outputPath)28 bool RawHeap::TranslateRawheap(const std::string &inputPath, const std::string &outputPath)
29 {
30 auto start = std::chrono::steady_clock::now();
31 FileReader file;
32 if (!file.Initialize(inputPath)) {
33 return false;
34 }
35
36 uint64_t fileSize = FileReader::GetFileSize(inputPath);
37 if (!file.CheckAndGetHeaderAt(fileSize - sizeof(uint64_t), 0)) {
38 LOG_ERROR_ << "Read rawheap file header failed!";
39 return false;
40 }
41
42 MetaParser metaParser;
43 if (!ParseMetaData(file, &metaParser)) {
44 return false;
45 }
46
47 RawHeap *rawheap = ParseRawheap(file, &metaParser);
48 if (rawheap == nullptr) {
49 return false;
50 }
51
52 if (!rawheap->Parse(file, file.GetHeaderLeft()) || !rawheap->Translate()) {
53 delete rawheap;
54 return false;
55 }
56
57 StreamWriter writer;
58 if (!writer.Initialize(outputPath)) {
59 delete rawheap;
60 return false;
61 }
62
63 HeapSnapshotJSONSerializer::Serialize(rawheap, &writer);
64 delete rawheap;
65 auto end = std::chrono::steady_clock::now();
66 int duration = (int)std::chrono::duration<double>(end - start).count();
67 LOG_INFO_ << "file save to " << outputPath << ", cost " << std::to_string(duration) << 's';
68 return true;
69 }
70
ParseMetaData(FileReader & file,MetaParser * parser)71 bool RawHeap::ParseMetaData(FileReader &file, MetaParser *parser)
72 {
73 if (!file.CheckAndGetHeaderAt(file.GetFileSize() - sizeof(uint64_t), 0)) {
74 LOG_ERROR_ << "rawheap header error!";
75 return false;
76 }
77
78 std::vector<char> metadata(file.GetHeaderRight());
79 if (!file.Seek(file.GetHeaderLeft()) || !file.Read(metadata.data(), file.GetHeaderRight())) {
80 LOG_ERROR_ << "read metadata failed!";
81 return false;
82 }
83
84 cJSON *json = cJSON_Parse(metadata.data());
85 if (json == nullptr) {
86 LOG_ERROR_ << "metadata cjson parse failed!";
87 return false;
88 }
89
90 bool ret = parser->Parse(json);
91 cJSON_Delete(json);
92 return ret;
93 }
94
ParseRawheap(FileReader & file,MetaParser * metaParser)95 RawHeap *RawHeap::ParseRawheap(FileReader &file, MetaParser *metaParser)
96 {
97 Version version;
98 if (!version.Parse(RawHeap::ReadVersion(file))) {
99 return nullptr;
100 }
101
102 if (VERSION < version) {
103 LOG_ERROR_ << "The rawheap file's version " << version.ToString()
104 << " is not matched the current rawheap translator,"
105 << " please use the newest version of the translator!";
106 return nullptr;
107 }
108
109 if (Version(1, 0, 0) < version) {
110 return new RawHeapTranslateV2(metaParser);
111 }
112
113 return new RawHeapTranslateV1(metaParser);
114 }
115
ReadVersion(FileReader & file)116 std::string RawHeap::ReadVersion(FileReader &file)
117 {
118 uint32_t size = 8; // 8: version size
119 std::vector<char> version(size);
120 if (!file.Seek(0) || !file.Read(version.data(), size)) {
121 return "";
122 }
123 if (*reinterpret_cast<uint64_t *>(version.data()) == 0) {
124 return "1.0.0";
125 }
126 LOG_INFO_ << "current rawheap version is " << version.data();
127 return std::string(version.data());
128 }
129
GetNodes()130 std::vector<Node *>* RawHeap::GetNodes()
131 {
132 return &nodes_;
133 }
134
GetEdges()135 std::vector<Edge *>* RawHeap::GetEdges()
136 {
137 return &edges_;
138 }
139
GetNodeCount()140 size_t RawHeap::GetNodeCount()
141 {
142 return nodes_.size();
143 }
144
GetEdgeCount()145 size_t RawHeap::GetEdgeCount()
146 {
147 return edges_.size();
148 }
149
GetStringTable()150 StringHashMap *RawHeap::GetStringTable()
151 {
152 return strTable_;
153 }
154
GetVersion()155 std::string RawHeap::GetVersion()
156 {
157 return version_;
158 }
159
CreateNode()160 Node *RawHeap::CreateNode()
161 {
162 Node *node = new Node(nodeIndex_++);
163 nodes_.push_back(node);
164 return node;
165 }
166
InsertEdge(Node * toNode,uint32_t indexOrStrId,EdgeType type)167 void RawHeap::InsertEdge(Node *toNode, uint32_t indexOrStrId, EdgeType type)
168 {
169 Edge *edge = new Edge(toNode, indexOrStrId, type);
170 edges_.push_back(edge);
171 }
172
InsertAndGetStringId(const std::string & str)173 StringId RawHeap::InsertAndGetStringId(const std::string &str)
174 {
175 return strTable_->InsertStrAndGetStringId(str);
176 }
177
SetVersion(const std::string & version)178 void RawHeap::SetVersion(const std::string &version)
179 {
180 version_ = version;
181 }
182
ReadSectionInfo(FileReader & file,uint32_t offset,std::vector<uint32_t> & section)183 bool RawHeap::ReadSectionInfo(FileReader &file, uint32_t offset, std::vector<uint32_t> §ion)
184 {
185 if (!file.CheckAndGetHeaderAt(offset - sizeof(uint64_t), sizeof(uint32_t))) {
186 LOG_ERROR_ << "sections header error!";
187 return false;
188 }
189
190 uint32_t sectionHeaderOffset = offset - (file.GetHeaderLeft() + 2) * sizeof(uint32_t);
191 section.resize(file.GetHeaderLeft());
192 if (!file.Seek(sectionHeaderOffset) || !file.ReadArray(section, file.GetHeaderLeft())) {
193 LOG_ERROR_ << "read sections error!";
194 return false;
195 }
196
197 return true;
198 }
199
~RawHeapTranslateV1()200 RawHeapTranslateV1::~RawHeapTranslateV1()
201 {
202 for (auto &mem : mem_) {
203 delete[] mem;
204 }
205 mem_.clear();
206 sections_.clear();
207 nodesMap_.clear();
208 }
209
Parse(FileReader & file,uint32_t rawheapFileSize)210 bool RawHeapTranslateV1::Parse(FileReader &file, uint32_t rawheapFileSize)
211 {
212 if (!ReadSectionInfo(file, rawheapFileSize, sections_) || !ReadRootTable(file) || !ReadStringTable(file)) {
213 return false;
214 }
215
216 // 4: object table section start from 4, step is 2
217 for (size_t i = 4; i < sections_.size(); i += 2) {
218 if (!ReadObjectTable(file, sections_[i], sections_[i + 1])) {
219 return false;
220 }
221 }
222 return true;
223 }
224
Translate()225 bool RawHeapTranslateV1::Translate()
226 {
227 auto nodes = GetNodes();
228 for (auto it = nodes->begin() + 1; it != nodes->end(); ++it) {
229 Node *node = *it;
230 Node *hclass = FindNode(ByteToU64(node->data));
231 if (hclass == nullptr) {
232 LOG_ERROR_ << "missed hclass, node_id=" << node->nodeId;
233 return false;
234 }
235
236 JSType type = metaParser_->GetJSTypeFromHClass(hclass);
237 FillNodes(node, type);
238 CreateHClassEdge(node, hclass);
239 if (!metaParser_->IsString(type)) {
240 BuildEdges(node, type);
241 }
242 }
243 LOG_INFO_ << "success!";
244 return true;
245 }
246
ReadRootTable(FileReader & file)247 bool RawHeapTranslateV1::ReadRootTable(FileReader &file)
248 {
249 if (!file.CheckAndGetHeaderAt(sections_[0], sizeof(uint64_t))) {
250 LOG_ERROR_ << "root table header error!";
251 return false;
252 }
253
254 std::vector<uint64_t> roots(file.GetHeaderLeft());
255 if (!file.ReadArray(roots, file.GetHeaderLeft())) {
256 LOG_ERROR_ << "read root addr error!";
257 return false;
258 }
259
260 AddSyntheticRootNode(roots);
261 LOG_INFO_ << "root node count " << file.GetHeaderLeft();
262 return true;
263 }
264
ReadStringTable(FileReader & file)265 bool RawHeapTranslateV1::ReadStringTable(FileReader &file)
266 {
267 // 2: string table start from sections_[2]
268 if (!file.CheckAndGetHeaderAt(sections_[2], 0)) {
269 LOG_ERROR_ << "string table header error!";
270 return false;
271 }
272
273 uint32_t strCnt = file.GetHeaderLeft();
274 for (uint32_t i = 0; i < strCnt; ++i) {
275 ParseStringTable(file);
276 }
277
278 LOG_INFO_ << "string table count " << strCnt;
279 return true;
280 }
281
ReadObjectTable(FileReader & file,uint32_t offset,uint32_t totalSize)282 bool RawHeapTranslateV1::ReadObjectTable(FileReader &file, uint32_t offset, uint32_t totalSize)
283 {
284 if (!file.CheckAndGetHeaderAt(offset, sizeof(AddrTableItem))) {
285 LOG_ERROR_ << "object table header error!";
286 return false;
287 }
288
289 uint32_t tableSize = file.GetHeaderLeft() * file.GetHeaderRight();
290 uint32_t memSize = totalSize - tableSize - sizeof(uint64_t);
291 std::vector<char> objTableData(tableSize);
292 char *mem = new char[memSize];
293 if (!file.Read(objTableData.data(), tableSize) || !file.Read(mem, memSize)) {
294 delete[] mem;
295 return false;
296 }
297
298 mem_.push_back(mem);
299 char *data = objTableData.data();
300 for (uint32_t i = 0; i < file.GetHeaderLeft(); ++i) {
301 uint64_t addr = ByteToU64(data);
302 Node *node = FindOrCreateNode(addr);
303 data += sizeof(uint64_t);
304
305 node->nodeId = ByteToU64(data);
306 data += sizeof(uint64_t);
307
308 node->size = ByteToU32(data);
309 data += sizeof(uint32_t);
310
311 uint32_t memOffset = ByteToU32(data) - tableSize;
312 data += sizeof(uint32_t);
313
314 if (memOffset + sizeof(uint64_t) > memSize) {
315 LOG_ERROR_ << "object memory offset error!";
316 return false;
317 }
318
319 node->data = mem + memOffset;
320 }
321 LOG_INFO_ << "section objects count " << file.GetHeaderLeft();
322 return true;
323 }
324
ParseStringTable(FileReader & file)325 bool RawHeapTranslateV1::ParseStringTable(FileReader &file)
326 {
327 constexpr int HEADER_SIZE = sizeof(uint64_t) / sizeof(uint32_t);
328 std::vector<uint32_t> header(HEADER_SIZE);
329 if (!file.ReadArray(header, HEADER_SIZE)) {
330 return false;
331 }
332
333 std::vector<uint64_t> objects(header[1]);
334 if (!file.ReadArray(objects, header[1])) {
335 LOG_ERROR_ << "read objects addr error!";
336 return false;
337 }
338
339 std::vector<char> str(header[0] + 1);
340 if (!file.Read(str.data(), header[0] + 1)) {
341 LOG_ERROR_ << "read string error!";
342 return false;
343 }
344
345 StringId strId = InsertAndGetStringId(std::string(str.data()));
346 SetNodeStringId(objects, strId);
347 return true;
348 }
349
AddSyntheticRootNode(std::vector<uint64_t> & roots)350 void RawHeapTranslateV1::AddSyntheticRootNode(std::vector<uint64_t> &roots)
351 {
352 Node *syntheticRoot = CreateNode();
353 syntheticRoot->nodeId = 1; // 1: means root node
354 syntheticRoot->type = 9; // 9: means SYNTHETIC node type
355 syntheticRoot->strId = InsertAndGetStringId("SyntheticRoot");
356 syntheticRoot->edgeCount = roots.size();
357
358 StringId strId = InsertAndGetStringId("-subroot-");
359 EdgeType type = EdgeType::SHORTCUT;
360 for (auto addr : roots) {
361 Node *root = FindOrCreateNode(addr);
362 InsertEdge(root, strId, type);
363 }
364 }
365
SetNodeStringId(const std::vector<uint64_t> & objects,StringId strId)366 void RawHeapTranslateV1::SetNodeStringId(const std::vector<uint64_t> &objects, StringId strId)
367 {
368 for (auto addr : objects) {
369 Node *node = FindOrCreateNode(addr);
370 node->strId = strId;
371 }
372 }
373
FindOrCreateNode(uint64_t addr)374 Node *RawHeapTranslateV1::FindOrCreateNode(uint64_t addr)
375 {
376 Node *node = FindNode(addr);
377 if (node != nullptr) {
378 return node;
379 }
380 node = CreateNode();
381 nodesMap_.emplace(addr, node);
382 return node;
383 }
384
FindNode(uint64_t addr)385 Node *RawHeapTranslateV1::FindNode(uint64_t addr)
386 {
387 auto it = nodesMap_.find(addr);
388 if (it != nodesMap_.end()) {
389 return it->second;
390 }
391 return nullptr;
392 }
393
FillNodes(Node * node,JSType type)394 void RawHeapTranslateV1::FillNodes(Node *node, JSType type)
395 {
396 node->type = metaParser_->GetNodeType(type);
397 node->nativeSize = metaParser_->GetNativateSize(node, type);
398 if (node->strId >= StringHashMap::CUSTOM_STRID_START) {
399 StringKey stringKey = GetStringTable()->GetKeyByStringId(node->strId);
400 std::string nodeName = GetStringTable()->GetStringByKey(stringKey);
401 if (nodeName.find("_GLOBAL") != std::string::npos) {
402 node->type = FRAMEWORK_NODETYPE;
403 }
404 } else if (!metaParser_->IsString(type)) {
405 std::string name = metaParser_->GetTypeName(type);
406 std::transform(name.begin(), name.end(), name.begin(), ::tolower);
407 node->strId = InsertAndGetStringId(name);
408 }
409 }
410
BuildEdges(Node * node,JSType type)411 void RawHeapTranslateV1::BuildEdges(Node *node, JSType type)
412 {
413 if (metaParser_->IsGlobalEnv(type)) {
414 BuildGlobalEnvEdges(node, type);
415 } else if (metaParser_->IsArray(type)) {
416 BuildArrayEdges(node, type);
417 } else {
418 BuildFieldEdges(node, type);
419 if (metaParser_->IsJSObject(type)) {
420 BuildJSObjectEdges(node, type);
421 }
422 }
423 }
424
BuildGlobalEnvEdges(Node * node,JSType type)425 void RawHeapTranslateV1::BuildGlobalEnvEdges(Node *node, JSType type)
426 {
427 uint32_t offset = sizeof(uint64_t);
428 uint32_t index = 0;
429 while ((offset + sizeof(uint64_t)) <= node->size) {
430 uint64_t addr = ByteToU64(node->data + offset);
431 offset += sizeof(uint64_t);
432 EdgeType edgeType = GenerateEdgeTypeAndRemoveWeak(node, type, addr);
433 CreateEdge(node, addr, index++, edgeType);
434 }
435 }
436
BuildArrayEdges(Node * node,JSType type)437 void RawHeapTranslateV1::BuildArrayEdges(Node *node, JSType type)
438 {
439 BitField *bitField = metaParser_->GetBitField();
440 uint32_t lengthOffset = bitField->taggedArrayLengthField.offset;
441 uint32_t dataOffset = bitField->taggedArrayDataField.offset;
442 uint32_t step = bitField->taggedArrayDataField.size;
443
444 uint32_t len = ByteToU32(node->data + lengthOffset);
445 if (step != sizeof(uint64_t) || len <= 0) {
446 return;
447 }
448
449 uint32_t offset = dataOffset;
450 uint32_t index = 0;
451 while (index < len && offset + step <= node->size) {
452 uint64_t addr = ByteToU64(node->data + offset);
453 offset += step;
454 EdgeType edgeType = GenerateEdgeTypeAndRemoveWeak(node, type, addr);
455 CreateEdge(node, addr, index++, edgeType);
456 }
457 }
458
BuildFieldEdges(Node * node,JSType type)459 void RawHeapTranslateV1::BuildFieldEdges(Node *node, JSType type)
460 {
461 MetaData *meta = metaParser_->GetMetaData(type);
462 if (meta == nullptr) {
463 return;
464 }
465
466 for (const auto &field : meta->fields) {
467 if (field.size != sizeof(uint64_t)) {
468 continue;
469 }
470 uint64_t addr = ByteToU64(node->data + field.offset);
471 EdgeType edgeType = GenerateEdgeTypeAndRemoveWeak(node, type, addr);
472 StringId strId = InsertAndGetStringId(field.name);
473 CreateEdge(node, addr, strId, edgeType);
474 }
475 }
476
BuildJSObjectEdges(Node * node,JSType type)477 void RawHeapTranslateV1::BuildJSObjectEdges(Node *node, JSType type)
478 {
479 MetaData *meta = metaParser_->GetMetaData(type);
480 if (meta == nullptr) {
481 return;
482 }
483
484 StringId inlinePropertyStrId = InsertAndGetStringId("InlineProperty");
485 uint32_t offset = meta->endOffset;
486 while (offset + sizeof(uint64_t) <= node->size) {
487 uint64_t addr = ByteToU64(node->data + offset);
488 EdgeType edgeType = GenerateEdgeTypeAndRemoveWeak(node, type, addr);
489 CreateEdge(node, addr, inlinePropertyStrId, edgeType);
490 offset += sizeof(uint64_t);
491 }
492 }
493
CreateEdge(Node * node,uint64_t addr,uint32_t nameOrIndex,EdgeType type)494 void RawHeapTranslateV1::CreateEdge(Node *node, uint64_t addr, uint32_t nameOrIndex, EdgeType type)
495 {
496 Node *to = FindNode(addr);
497 if (to == nullptr || to == node) {
498 return;
499 }
500 InsertEdge(to, nameOrIndex, type);
501 node->edgeCount++;
502 }
503
CreateHClassEdge(Node * node,Node * hclass)504 void RawHeapTranslateV1::CreateHClassEdge(Node *node, Node *hclass)
505 {
506 if (node->nodeId == hclass->nodeId) {
507 return;
508 }
509 static StringId hclassStrId = InsertAndGetStringId("hclass");
510 InsertEdge(hclass, hclassStrId, EdgeType::DEFAULT);
511 node->edgeCount++;
512 }
513
GenerateEdgeTypeAndRemoveWeak(Node * node,JSType type,uint64_t & addr)514 EdgeType RawHeapTranslateV1::GenerateEdgeTypeAndRemoveWeak(Node *node, JSType type, uint64_t &addr)
515 {
516 EdgeType edgeType = EdgeType::DEFAULT;
517 if (IsWeak(addr)) {
518 RemoveWeak(addr);
519 edgeType = EdgeType::WEAK;
520 }
521 if (metaParser_->IsArray(type)) {
522 edgeType = EdgeType::ELEMENT;
523 }
524 return edgeType;
525 }
526
IsHeapObject(uint64_t addr)527 bool RawHeapTranslateV1::IsHeapObject(uint64_t addr)
528 {
529 return ((addr & TAG_HEAPOBJECT_MASK) == 0U);
530 }
531
IsWeak(uint64_t addr)532 bool RawHeapTranslateV1::IsWeak(uint64_t addr)
533 {
534 return (addr & TAG_WEAK_MASK) == TAG_WEAK;
535 }
536
RemoveWeak(uint64_t & addr)537 void RawHeapTranslateV1::RemoveWeak(uint64_t &addr)
538 {
539 addr &= (~TAG_WEAK);
540 }
541
~RawHeapTranslateV2()542 RawHeapTranslateV2::~RawHeapTranslateV2()
543 {
544 delete[] mem_;
545 sections_.clear();
546 nodesMap_.clear();
547 }
548
Parse(FileReader & file,uint32_t rawheapFileSize)549 bool RawHeapTranslateV2::Parse(FileReader &file, uint32_t rawheapFileSize)
550 {
551 return ReadSectionInfo(file, rawheapFileSize, sections_) &&
552 ReadObjectTable(file) && ReadRootTable(file) && ReadStringTable(file);
553 }
554
Translate()555 bool RawHeapTranslateV2::Translate()
556 {
557 FillNodes();
558 auto nodes = GetNodes();
559 size_t size = nodes->size();
560 for (size_t i = 1; i < size; ++i) {
561 Node *node = (*nodes)[i];
562 Node *hclass = GetNextEdgeTo();
563 if (hclass == nullptr) {
564 LOG_ERROR_ << "missed hclass, node_id=" << node->nodeId;
565 return false;
566 } else if (hclass->nodeId != node->nodeId) {
567 CreateEdge(node, hclass, InsertAndGetStringId("hclass"), EdgeType::DEFAULT);
568 }
569
570 if (metaParser_->IsString(node->jsType)) {
571 continue;
572 }
573 BuildEdges(node);
574 }
575 LOG_INFO_ << "success!";
576 return true;
577 }
578
ReadRootTable(FileReader & file)579 bool RawHeapTranslateV2::ReadRootTable(FileReader &file)
580 {
581 if (!file.CheckAndGetHeaderAt(sections_[0], sizeof(uint32_t))) {
582 LOG_ERROR_ << "root table header error!";
583 return false;
584 }
585
586 std::vector<uint32_t> roots(file.GetHeaderLeft());
587 if (!file.ReadArray(roots, file.GetHeaderLeft())) {
588 LOG_ERROR_ << "read root addr error!";
589 return false;
590 }
591
592 AddSyntheticRootNode(roots);
593 LOG_INFO_ << "root node count " << file.GetHeaderLeft();
594 return true;
595 }
596
ReadStringTable(FileReader & file)597 bool RawHeapTranslateV2::ReadStringTable(FileReader &file)
598 {
599 // 2: index in sections means the offset of string table
600 if (!file.CheckAndGetHeaderAt(sections_[2], 0)) {
601 LOG_ERROR_ << "string table header error!";
602 return false;
603 }
604
605 uint32_t strCnt = file.GetHeaderLeft();
606 for (uint32_t i = 0; i < strCnt; ++i) {
607 ParseStringTable(file);
608 }
609
610 LOG_INFO_ << "string table count " << strCnt;
611 return true;
612 }
613
ReadObjectTable(FileReader & file)614 bool RawHeapTranslateV2::ReadObjectTable(FileReader &file)
615 {
616 // 4: index in sections means the offset of object table
617 if (!file.CheckAndGetHeaderAt(sections_[4], sizeof(AddrTableItemV2))) {
618 LOG_ERROR_ << "object table header error!";
619 return false;
620 }
621
622 syntheticRoot_ = CreateNode();
623 uint32_t tableSize = file.GetHeaderLeft() * sizeof(AddrTableItemV2);
624 // 5: index in sections means the total size of object table
625 memSize_ = sections_[5] - tableSize - sizeof(uint64_t);
626 std::vector<char> objTableData(tableSize);
627 mem_ = new char[memSize_];
628 if (!file.Read(objTableData.data(), tableSize) || !file.Read(mem_, memSize_)) {
629 LOG_ERROR_ << "read object table failed!";
630 return false;
631 }
632
633 char *tableData = objTableData.data();
634 for (uint32_t i = 0; i < file.GetHeaderLeft(); ++i) {
635 AddrTableItemV2 table = {
636 ByteToU32(tableData),
637 ByteToU32(tableData + sizeof(uint32_t)),
638 ByteToU64(tableData + sizeof(uint64_t)),
639 ByteToU32(tableData + sizeof(uint64_t) * 2),
640 ByteToU32(tableData + sizeof(uint64_t) * 2 + sizeof(uint32_t))
641 };
642
643 Node *node = CreateNode();
644 nodesMap_.emplace(table.syntheticAddr, node);
645 node->size = table.size;
646 node->nodeId = table.nodeId;
647 node->nativeSize = table.nativeSize;
648 node->jsType = static_cast<uint8_t>(table.type);
649 tableData += sizeof(AddrTableItemV2);
650 }
651
652 LOG_INFO_ << "objects table count " << file.GetHeaderLeft();
653 return true;
654 }
655
ParseStringTable(FileReader & file)656 bool RawHeapTranslateV2::ParseStringTable(FileReader &file)
657 {
658 constexpr int HEADER_SIZE = sizeof(uint64_t) / sizeof(uint32_t);
659 std::vector<uint32_t> header(HEADER_SIZE);
660 if (!file.ReadArray(header, HEADER_SIZE)) {
661 return false;
662 }
663
664 std::vector<uint32_t> objects(header[1]);
665 if (!file.ReadArray(objects, header[1])) {
666 LOG_ERROR_ << "read objects addr error!";
667 return false;
668 }
669
670 std::vector<char> str(header[0] + 1);
671 if (!file.Read(str.data(), header[0] + 1)) {
672 LOG_ERROR_ << "read string error!";
673 return false;
674 }
675
676 std::string name(str.data());
677 StringId strId = InsertAndGetStringId(name);
678 for (auto addr : objects) {
679 Node *node = FindNode(addr);
680 if (node == nullptr) {
681 continue;
682 }
683 node->strId = strId;
684 if (name.find("_GLOBAL") != std::string::npos) {
685 node->type = FRAMEWORK_NODETYPE;
686 }
687 }
688 return true;
689 }
690
AddSyntheticRootNode(std::vector<uint32_t> & roots)691 void RawHeapTranslateV2::AddSyntheticRootNode(std::vector<uint32_t> &roots)
692 {
693 syntheticRoot_->nodeId = 1; // 1: means root node
694 syntheticRoot_->type = 9; // 9: means SYNTHETIC node type
695 syntheticRoot_->strId = InsertAndGetStringId("SyntheticRoot");
696 syntheticRoot_->edgeCount = roots.size();
697
698 StringId strId = InsertAndGetStringId("-subroot-");
699 EdgeType type = EdgeType::SHORTCUT;
700 for (auto addr : roots) {
701 Node *root = FindNode(addr);
702 if (root == nullptr) {
703 continue;
704 }
705 InsertEdge(root, strId, type);
706 }
707 }
708
FindNode(uint32_t addr)709 Node *RawHeapTranslateV2::FindNode(uint32_t addr)
710 {
711 auto it = nodesMap_.find(addr);
712 if (it != nodesMap_.end()) {
713 return it->second;
714 }
715 return nullptr;
716 }
717
FillNodes()718 void RawHeapTranslateV2::FillNodes()
719 {
720 auto nodes = GetNodes();
721 for (auto it = nodes->begin() + 1; it != nodes->end(); it++) {
722 if ((*it)->type == DEFAULT_NODETYPE) {
723 (*it)->type = metaParser_->GetNodeType((*it)->jsType);
724 }
725
726 if ((*it)->strId >= StringHashMap::CUSTOM_STRID_START || metaParser_->IsString((*it)->jsType)) {
727 continue;
728 }
729 std::string name = metaParser_->GetTypeName((*it)->jsType);
730 std::transform(name.begin(), name.end(), name.begin(), ::tolower);
731 (*it)->strId = InsertAndGetStringId(name);
732 }
733 }
734
BuildEdges(Node * node)735 void RawHeapTranslateV2::BuildEdges(Node *node)
736 {
737 if (metaParser_->IsArray(node->jsType)) {
738 BuildArrayEdges(node);
739 } else {
740 std::vector<Node *> refs;
741 for (uint32_t offset = sizeof(uint64_t); offset < node->size; offset += sizeof(uint64_t)) {
742 refs.push_back(GetNextEdgeTo());
743 }
744 BuildFieldEdges(node, refs);
745 }
746 }
747
BuildArrayEdges(Node * node)748 void RawHeapTranslateV2::BuildArrayEdges(Node *node)
749 {
750 uint32_t index = 0;
751 for (uint32_t offset = sizeof(uint64_t); offset < node->size; offset += sizeof(uint64_t)) {
752 Node *ref = GetNextEdgeTo();
753 if (ref == nullptr) {
754 continue;
755 }
756 CreateEdge(node, ref, index++, EdgeType::ELEMENT);
757 }
758 }
759
BuildFieldEdges(Node * node,std::vector<Node * > & refs)760 void RawHeapTranslateV2::BuildFieldEdges(Node *node, std::vector<Node *> &refs)
761 {
762 MetaData *meta = metaParser_->GetMetaData(node->jsType);
763 if (meta == nullptr) {
764 LOG_ERROR_ << "js type error, type=" << static_cast<int>(node->jsType);
765 return;
766 }
767
768 for (auto &field : meta->fields) {
769 size_t index = field.offset / sizeof(uint64_t) - 1;
770 if (index >= refs.size() || index < 0) {
771 continue;
772 }
773
774 Node *to = refs[index];
775 if (to == nullptr) {
776 continue;
777 }
778
779 StringId strId = InsertAndGetStringId(field.name);
780 CreateEdge(node, to, strId, EdgeType::DEFAULT);
781 }
782
783 if (metaParser_->IsJSObject(node->jsType)) {
784 BuildJSObjectEdges(node, refs, meta->endOffset);
785 }
786 }
787
BuildJSObjectEdges(Node * node,std::vector<Node * > & refs,uint32_t endOffset)788 void RawHeapTranslateV2::BuildJSObjectEdges(Node *node, std::vector<Node *> &refs, uint32_t endOffset)
789 {
790 size_t index = endOffset / sizeof(uint64_t) - 1;
791 for (size_t i = index; i < refs.size(); ++i) {
792 Node *ref = refs[i];
793 if (ref == nullptr) {
794 continue;
795 }
796 CreateEdge(node, ref, InsertAndGetStringId("InlineProperty"), EdgeType::DEFAULT);
797 }
798 }
799
CreateEdge(Node * node,Node * to,uint32_t nameOrIndex,EdgeType type)800 void RawHeapTranslateV2::CreateEdge(Node *node, Node *to, uint32_t nameOrIndex, EdgeType type)
801 {
802 InsertEdge(to, nameOrIndex, type);
803 node->edgeCount++;
804 }
805
GetNextEdgeTo()806 Node *RawHeapTranslateV2::GetNextEdgeTo()
807 {
808 if (memPos_ + 1 > memSize_) {
809 return nullptr;
810 }
811
812 uint8_t tag = *reinterpret_cast<uint8_t *>(mem_ + memPos_++);
813 if ((tag & ZERO_VALUE) == ZERO_VALUE) {
814 return nullptr;
815 }
816
817 if ((tag & INTL_VALUE) == INTL_VALUE) {
818 memPos_ += sizeof(uint32_t);
819 return nullptr;
820 }
821
822 if ((tag & DOUB_VALUE) == DOUB_VALUE) {
823 memPos_ += sizeof(uint64_t);
824 return nullptr;
825 }
826
827 Node *node = FindNode(ByteToU32(mem_ + memPos_ - 1));
828 memPos_ += sizeof(uint32_t) - 1;
829 return node;
830 }
831
GenerateEdgeType(Node * node)832 EdgeType RawHeapTranslateV2::GenerateEdgeType(Node *node)
833 {
834 EdgeType edgeType = EdgeType::DEFAULT;
835 if (metaParser_->IsArray(node->type)) {
836 edgeType = EdgeType::ELEMENT;
837 }
838 return edgeType;
839 }
840 }
841 // namespace rawheap_translate
842