• 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 <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> &section)
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