• 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 "function.h"
17 
18 #include "bytecode_optimizer/runtime_adapter.h"
19 #include "compiler/optimizer/ir_builder/ir_builder.h"
20 #include "libpandafile/method_data_accessor-inl.h"
21 #include "mem/arena_allocator.h"
22 #include "utils/logger.h"
23 
24 #include "configs/guard_context.h"
25 #include "graph_analyzer.h"
26 #include "inst_obf.h"
27 #include "program.h"
28 #include "util/assert_util.h"
29 #include "util/string_util.h"
30 
31 namespace {
32 constexpr std::string_view TAG = "[Function]";
33 constexpr std::string_view LINE_DELIMITER = ":";
34 constexpr std::string_view RECORD_DELIMITER = ".";
35 constexpr std::string_view SCOPE_DELIMITER = "#";
36 constexpr size_t SCOPE_AND_NAME_LEN = 2;
37 constexpr size_t MAX_LINE_NUMBER = 100000;
38 constexpr std::string_view ENTRY_FUNC_TAG = ".func_main_0";
39 constexpr std::string_view STATIC_INITIALIZER_TAG = ">#static_initializer";
40 constexpr std::string_view INSTANCE_INITIALIZER_TAG = ">#instance_initializer";
41 constexpr std::string_view CONSOLE_INS_VAR = "console";
42 constexpr std::string_view ANONYMOUS_FUNCTION_NAME = "^0";  // first anonymous function name
43 
44 const std::map<char, panda::guard::FunctionType> FUNCTION_TYPE_MAP = {
45     {'>', panda::guard::FunctionType::INSTANCE_FUNCTION},    {'<', panda::guard::FunctionType::STATIC_FUNCTION},
46     {'=', panda::guard::FunctionType::CONSTRUCTOR_FUNCTION}, {'*', panda::guard::FunctionType::NORMAL_FUNCTION},
47     {'%', panda::guard::FunctionType::ENUM_FUNCTION},        {'&', panda::guard::FunctionType::NAMESPACE_FUNCTION},
48 };
49 
50 /**
51  * Is it an entry function (func_main_0)
52  * @param functionIdx function Idx
53  * @return (true/false)
54  */
IsEntryMethod(const std::string & functionIdx)55 bool IsEntryMethod(const std::string &functionIdx)
56 {
57     return functionIdx.find(ENTRY_FUNC_TAG) != std::string::npos;
58 }
59 
60 /**
61  * Is it an implicit function (dynamically generated in bytecode, not reflected in source code)
62  * @param functionIdx function Idx
63  * @return (true/false)
64  */
IsImplicitMethod(const std::string & functionIdx)65 bool IsImplicitMethod(const std::string &functionIdx)
66 {
67     return functionIdx.find(INSTANCE_INITIALIZER_TAG) != std::string::npos ||
68            functionIdx.find(STATIC_INITIALIZER_TAG) != std::string::npos;
69 }
70 
71 /**
72  * Do not obfuscate the names of whitelist functions (internal instructions and associated properties need to be
73  * obfuscated)
74  * @param functionIdx function Idx
75  * @return (true/false)
76  */
IsWhiteListFunction(const std::string & functionIdx)77 bool IsWhiteListFunction(const std::string &functionIdx)
78 {
79     return IsEntryMethod(functionIdx) || IsImplicitMethod(functionIdx);
80 }
81 
GetConsoleLogInfoForStart(const std::vector<panda::pandasm::InsPtr> & insList,size_t & start,uint16_t & reg)82 bool GetConsoleLogInfoForStart(const std::vector<panda::pandasm::InsPtr> &insList, size_t &start, uint16_t &reg)
83 {
84     size_t i = 0;
85     while (i < insList.size()) {
86         auto &ins = insList[i];
87         if (ins->opcode == panda::pandasm::Opcode::TRYLDGLOBALBYNAME && ins->GetId(0) == CONSOLE_INS_VAR) {
88             size_t nextInsIndex = i + 1;
89             PANDA_GUARD_ASSERT_PRINT(nextInsIndex >= insList.size(), TAG, panda::guard::ErrorCode::GENERIC_ERROR,
90                                      "get console next ins get bad index:" << nextInsIndex);
91 
92             auto &nextIns = insList[nextInsIndex];
93             PANDA_GUARD_ASSERT_PRINT(nextIns->opcode != panda::pandasm::Opcode::STA, TAG,
94                                      panda::guard::ErrorCode::GENERIC_ERROR, "get console next ins get bad ins type");
95 
96             reg = nextIns->GetReg(0);
97             start = i;
98             return true;
99         }
100         i++;
101     }
102 
103     return false;
104 }
105 
HasMovInstForRange(const std::vector<panda::pandasm::InsPtr> & insList,size_t start,size_t end,uint16_t oriReg,uint16_t rangeReg)106 bool HasMovInstForRange(const std::vector<panda::pandasm::InsPtr> &insList, size_t start, size_t end, uint16_t oriReg,
107                         uint16_t rangeReg)
108 {
109     size_t i = end - 1;
110     while (i > start) {
111         auto &ins = insList[i];
112         if ((ins->opcode == panda::pandasm::Opcode::MOV) && (ins->GetReg(0) == rangeReg) &&
113             (ins->GetReg(1) == oriReg)) {
114             return true;
115         }
116         i--;
117     }
118     return false;
119 }
120 
GetConsoleLogInfoForEnd(const std::vector<panda::pandasm::InsPtr> & insList,size_t start,uint16_t reg,size_t & end)121 int GetConsoleLogInfoForEnd(const std::vector<panda::pandasm::InsPtr> &insList, size_t start, uint16_t reg, size_t &end)
122 {
123     size_t i = start + 1;
124     while (i < insList.size()) {
125         auto &ins = insList[i];
126         if ((ins->opcode == panda::pandasm::Opcode::CALLTHIS1 || ins->opcode == panda::pandasm::Opcode::CALLTHIS2 ||
127              ins->opcode == panda::pandasm::Opcode::CALLTHIS3) &&
128             ins->GetReg(0) == reg) {
129             end = i + 1;
130             return true;
131         }
132 
133         if ((ins->opcode == panda::pandasm::Opcode::CALLTHISRANGE) &&
134             HasMovInstForRange(insList, start, i, reg, ins->GetReg(0))) {
135             end = i + 1;
136             return true;
137         }
138 
139         i++;
140     }
141 
142     return false;
143 }
144 
145 /**
146  * Retrieve instruction information related to console. xxx from the instruction list [start, end]
147  * @param insList instruction list
148  * @param start console instruction start index
149  * @param end console instruction end index(not included)
150  * @return result code
151  */
GetConsoleLogInfo(const std::vector<panda::pandasm::InsPtr> & insList,size_t & start,size_t & end)152 bool GetConsoleLogInfo(const std::vector<panda::pandasm::InsPtr> &insList, size_t &start, size_t &end)
153 {
154     size_t startIndex = 0;
155     uint16_t reg = 0;  // console variable stored reg
156     size_t endIndex = 0;
157     if (!GetConsoleLogInfoForStart(insList, startIndex, reg)) {
158         return false;
159     }
160 
161     if (!GetConsoleLogInfoForEnd(insList, startIndex, reg, endIndex)) {
162         return false;
163     }
164 
165     start = startIndex;
166     end = endIndex;
167 
168     return true;
169 }
170 }  // namespace
171 
Init()172 void panda::guard::Function::Init()
173 {
174     /* e.g.
175      * idx_: &entry/src/main/ets/entryability/EntryAbility&.#~@0>#onCreate
176      * recordName_: &entry/src/main/ets/entryability/EntryAbility&
177      * rawName_: #~@0>#onCreate
178      * scopeTypeStr_: ~@0>
179      */
180     LOG(INFO, PANDAGUARD) << TAG << "Function:" << this->idx_;
181     this->obfIdx_ = this->idx_;
182     const auto &[recordName, rawName] = StringUtil::RSplitOnce(this->idx_, RECORD_DELIMITER.data());
183     PANDA_GUARD_ASSERT_PRINT(recordName.empty() || rawName.empty(), TAG, ErrorCode::GENERIC_ERROR,
184                              "split record and name get bad value");
185 
186     this->recordName_ = recordName;
187     this->rawName_ = rawName;
188 
189     this->InitBaseInfo();
190 
191     LOG(INFO, PANDAGUARD) << TAG << "idx:" << this->idx_;
192     LOG(INFO, PANDAGUARD) << TAG << "recordName:" << this->recordName_;
193     LOG(INFO, PANDAGUARD) << TAG << "rawName:" << this->rawName_;
194     LOG(INFO, PANDAGUARD) << TAG << "regsNum:" << this->regsNum_;
195     LOG(INFO, PANDAGUARD) << TAG << "startLine:" << this->startLine_;
196     LOG(INFO, PANDAGUARD) << TAG << "endLine:" << this->endLine_;
197     LOG(INFO, PANDAGUARD) << TAG << "component:" << (this->component_ ? "true" : "false");
198 
199     if (!this->useScope_) {
200         return;
201     }
202 
203     std::vector<std::string> scopeAndName = StringUtil::Split(rawName, SCOPE_DELIMITER.data());
204     PANDA_GUARD_ASSERT_PRINT(scopeAndName.empty() || scopeAndName.size() > SCOPE_AND_NAME_LEN, TAG,
205                              ErrorCode::GENERIC_ERROR, "split scope and name get bad len");
206 
207     this->scopeTypeStr_ = scopeAndName[0];
208     this->SetFunctionType(scopeAndName[0].back());
209     this->name_ = scopeAndName.size() > 1 ? scopeAndName[1] : ANONYMOUS_FUNCTION_NAME;
210 
211     if (StringUtil::IsAnonymousFunctionName(this->name_)) {
212         this->anonymous_ = true;
213     }
214 
215     this->obfName_ = this->name_;
216 
217     LOG(INFO, PANDAGUARD) << TAG << "scopeTypeStr:" << this->scopeTypeStr_;
218     LOG(INFO, PANDAGUARD) << TAG << "type:" << (int)this->type_;
219     LOG(INFO, PANDAGUARD) << TAG << "name:" << this->name_;
220     LOG(INFO, PANDAGUARD) << TAG << "anonymous:" << (this->anonymous_ ? "true" : "false");
221 }
222 
GetOriginFunction()223 panda::pandasm::Function &panda::guard::Function::GetOriginFunction()
224 {
225     return this->program_->prog_->function_table.at(this->obfIdx_);
226 }
227 
InitBaseInfo()228 void panda::guard::Function::InitBaseInfo()
229 {
230     const auto &func = this->GetOriginFunction();
231     this->name_ = this->idx_;
232     this->obfName_ = this->name_;
233     this->regsNum_ = func.regs_num;
234 
235     if (GuardContext::GetInstance()->GetGuardOptions()->IsCompactObfEnabled()) {
236         this->startLine_ = 1;
237         this->endLine_ = 1;
238     } else {
239         size_t startLineIndex = 0;
240         while (startLineIndex < func.ins.size()) {
241             const size_t lineNumber = func.ins[startLineIndex]->ins_debug.line_number;
242             if (lineNumber < MAX_LINE_NUMBER) {
243                 this->startLine_ = lineNumber;
244                 break;
245             }
246             startLineIndex++;
247         }
248 
249         size_t endLineIndex = func.ins.size() - 1;
250         while (endLineIndex >= startLineIndex) {
251             const size_t lineNumber = func.ins[endLineIndex]->ins_debug.line_number;
252             if (lineNumber < MAX_LINE_NUMBER) {
253                 this->endLine_ = lineNumber + 1;
254                 break;
255             }
256             endLineIndex--;
257         }
258     }
259 }
260 
SetFunctionType(char functionTypeCode)261 void panda::guard::Function::SetFunctionType(char functionTypeCode)
262 {
263     PANDA_GUARD_ASSERT_PRINT(FUNCTION_TYPE_MAP.find(functionTypeCode) == FUNCTION_TYPE_MAP.end(), TAG,
264                              ErrorCode::GENERIC_ERROR, "unsupported function type code:" << functionTypeCode);
265 
266     this->type_ = FUNCTION_TYPE_MAP.at(functionTypeCode);
267 }
268 
InitNameCacheScope()269 void panda::guard::Function::InitNameCacheScope()
270 {
271     this->SetNameCacheScope(this->name_);
272 }
273 
Build()274 void panda::guard::Function::Build()
275 {
276     if (IsEntryMethod(this->idx_)) {
277         return;
278     }
279 
280     LOG(INFO, PANDAGUARD) << TAG << "function build for " << this->idx_ << " start";
281 
282     this->InitNameCacheScope();
283 
284     LOG(INFO, PANDAGUARD) << TAG << "scope:" << (this->scope_ == TOP_LEVEL ? "TOP_LEVEL" : "Function");
285     LOG(INFO, PANDAGUARD) << TAG << "nameCacheScope:" << this->GetNameCacheScope();
286     LOG(INFO, PANDAGUARD) << TAG << "export:" << (this->export_ ? "true" : "false");
287 
288     LOG(INFO, PANDAGUARD) << TAG << "function build for " << this->idx_ << " end";
289 }
290 
IsWhiteListOrAnonymousFunction(const std::string & functionIdx) const291 bool panda::guard::Function::IsWhiteListOrAnonymousFunction(const std::string &functionIdx) const
292 {
293     return IsWhiteListFunction(functionIdx) || this->anonymous_;
294 }
295 
RefreshNeedUpdate()296 void panda::guard::Function::RefreshNeedUpdate()
297 {
298     this->needUpdate_ = true;
299     this->contentNeedUpdate_ = true;
300     this->nameNeedUpdate_ = TopLevelOptionEntity::NeedUpdate(*this) && !IsWhiteListOrAnonymousFunction(this->idx_);
301     LOG(INFO, PANDAGUARD) << TAG << "Function nameNeedUpdate: " << (this->nameNeedUpdate_ ? "true" : "false");
302 }
303 
EnumerateIns(const std::function<InsTraver> & callback)304 void panda::guard::Function::EnumerateIns(const std::function<InsTraver> &callback)
305 {
306     auto &func = this->GetOriginFunction();
307     for (size_t i = 0; i < func.ins.size(); i++) {
308         InstructionInfo info(this, func.ins[i].get(), i);
309         callback(info);
310     }
311     this->FreeGraph();
312 }
313 
UpdateReference()314 void panda::guard::Function::UpdateReference()
315 {
316     LOG(INFO, PANDAGUARD) << TAG << "update reference start:" << this->idx_;
317     this->EnumerateIns([&](InstructionInfo &info) -> void { InstObf::UpdateInst(info); });
318     LOG(INFO, PANDAGUARD) << TAG << "update reference end:" << this->idx_;
319 }
320 
UpdateAnnotationReference()321 void panda::guard::Function::UpdateAnnotationReference()
322 {
323     const auto &function = this->GetOriginFunction();
324     function.metadata->EnumerateAnnotations([this](pandasm::AnnotationData &annotation) {
325         const std::string annotationFullName = annotation.GetName();  // "recordName.annoName"
326         if (Annotation::IsWhiteListAnnotation(annotationFullName)) {
327             return;
328         }
329 
330         PANDA_GUARD_ASSERT_PRINT(!this->node_.has_value(), TAG, ErrorCode::GENERIC_ERROR,
331                                  "function associate node is invalid");
332         LOG(INFO, PANDAGUARD) << TAG << "update annotation:" << annotationFullName;
333         const auto node = this->node_.value();
334         // annotation reference name maybe contains namespace name such as: ns1.n2.annoName
335         const auto annoNameWithNamespace =
336             annotationFullName.substr(annotationFullName.find(node->name_) + node->name_.length() + 1);
337         LOG(INFO, PANDAGUARD) << TAG << "annoName:" << annoNameWithNamespace;
338         const auto annoNames = StringUtil::Split(annoNameWithNamespace, RECORD_DELIMITER.data());
339         auto obfAnnoName = node->obfName_;
340         for (auto &name : annoNames) {
341             obfAnnoName += RECORD_DELIMITER.data() + GuardContext::GetInstance()->GetNameMapping()->GetName(name);
342         }
343         LOG(INFO, PANDAGUARD) << TAG << "obfAnnoName:" << obfAnnoName;
344         annotation.SetName(obfAnnoName);
345 
346         auto &recordTable = this->program_->prog_->record_table;
347         if (recordTable.find(annotationFullName) != recordTable.end()) {
348             // update reference annotation record
349             LOG(INFO, PANDAGUARD) << TAG << "update reference record:" << annotationFullName;
350             auto entry = recordTable.extract(annotationFullName);
351             entry.key() = obfAnnoName;
352             entry.mapped().name = obfAnnoName;
353             entry.mapped().metadata->SetAccessFlags(panda::ACC_ANNOTATION);
354             recordTable.insert(std::move(entry));
355         }
356     });
357 }
358 
RemoveConsoleLog()359 void panda::guard::Function::RemoveConsoleLog()
360 {
361     auto &insList = this->GetOriginFunction().ins;
362     size_t start = 0;
363     size_t end = 0;
364     while (GetConsoleLogInfo(insList, start, end)) {
365         LOG(INFO, PANDAGUARD) << TAG << "remove console log for:" << this->idx_;
366         LOG(INFO, PANDAGUARD) << TAG << "found console ins range:[" << start << ", " << end << ")";
367         PANDA_GUARD_ASSERT_PRINT(end >= insList.size(), TAG, ErrorCode::GENERIC_ERROR,
368                                  "bad end ins index for console:" << end);
369         insList.erase(insList.begin() + start, insList.begin() + end);
370     }
371 }
372 
RemoveLineNumber()373 void panda::guard::Function::RemoveLineNumber()
374 {
375     for (auto &inst : this->GetOriginFunction().ins) {
376         inst->ins_debug.line_number = 1;
377     }
378 }
379 
FillInstInfo(size_t index,InstructionInfo & instInfo)380 void panda::guard::Function::FillInstInfo(size_t index, InstructionInfo &instInfo)
381 {
382     auto &func = this->GetOriginFunction();
383     PANDA_GUARD_ASSERT_PRINT(index >= func.ins.size(), TAG, ErrorCode::GENERIC_ERROR, "out of range index: " << index);
384 
385     instInfo.function_ = this;
386     instInfo.index_ = index;
387     instInfo.ins_ = func.ins[index].get();
388 }
389 
ExtractNames(std::set<std::string> & strings) const390 void panda::guard::Function::ExtractNames(std::set<std::string> &strings) const
391 {
392     strings.emplace(this->name_);
393     for (const auto &[_, property] : this->propertyTable_) {
394         property->ExtractNames(strings);
395     }
396 
397     for (const auto &property : this->variableProperties_) {
398         property->ExtractNames(strings);
399     }
400 
401     if (GuardContext::GetInstance()->GetGuardOptions()->IsDecoratorObfEnabled()) {
402         for (const auto &property : this->objectDecoratorProperties_) {
403             property->ExtractNames(strings);
404         }
405     }
406 }
407 
SetExportAndRefreshNeedUpdate(bool isExport)408 void panda::guard::Function::SetExportAndRefreshNeedUpdate(bool isExport)
409 {
410     for (const auto &[_, property] : this->propertyTable_) {
411         property->SetExportAndRefreshNeedUpdate(isExport);
412     }
413 
414     Entity::SetExportAndRefreshNeedUpdate(isExport);
415 }
416 
GetLines() const417 std::string panda::guard::Function::GetLines() const
418 {
419     return LINE_DELIMITER.data() + std::to_string(this->startLine_) + LINE_DELIMITER.data() +
420            std::to_string(this->endLine_);
421 }
422 
UpdateName(const std::shared_ptr<Node> & node)423 void panda::guard::Function::UpdateName(const std::shared_ptr<Node> &node)
424 {
425     std::string obfRawName;
426     // The judgment here cannot be moved to the outer layer. The function here should not only confuse its own name, but
427     // also the file name Even if the file is kept, The function name may also be modified due to file name confusion,
428     // and the related logic still needs to be executed by the function itself
429     if (node->contentNeedUpdate_ && this->nameNeedUpdate_) {
430         /* e.g.
431          * #~@0=#EntryAbility
432          *  name_: EntryAbility
433          *  scopeTypeStr_: ~@0=
434          *  obfName_: a
435          *  obfRawName: #~@0=#a
436          */
437         this->obfName_ = GuardContext::GetInstance()->GetNameMapping()->GetName(this->name_);
438         obfRawName = SCOPE_DELIMITER.data() + this->scopeTypeStr_ + SCOPE_DELIMITER.data() + this->obfName_;
439     } else {
440         // e.g. rawName_: #~@0>@1*#
441         obfRawName = this->rawName_;
442     }
443 
444     this->obfIdx_ = node->obfName_ + RECORD_DELIMITER.data() + obfRawName;
445 }
446 
UpdateDefine() const447 void panda::guard::Function::UpdateDefine() const
448 {
449     bool obfuscated = false;
450 
451     for (auto &defineIns : this->defineInsList_) {
452         if (!defineIns.IsValid()) {
453             LOG(INFO, PANDAGUARD) << TAG << "no bind define ins, ignore update define";
454             continue;
455         }
456 
457         // definefunc, definemethod for function, defineclasswithbuffer, callruntime.definesendableclass for constructor
458         PANDA_GUARD_ASSERT_PRINT(defineIns.ins_->opcode != pandasm::Opcode::DEFINEFUNC &&
459                                      defineIns.ins_->opcode != pandasm::Opcode::DEFINECLASSWITHBUFFER &&
460                                      defineIns.ins_->opcode != pandasm::Opcode::CALLRUNTIME_DEFINESENDABLECLASS &&
461                                      defineIns.ins_->opcode != pandasm::Opcode::DEFINEMETHOD,
462                                  TAG, ErrorCode::GENERIC_ERROR, "get bad ins type");
463 
464         defineIns.ins_->GetId(0) = this->obfIdx_;
465         obfuscated = true;
466     }
467 
468     if (obfuscated) {
469         this->program_->prog_->strings.emplace(this->obfIdx_);
470     }
471 }
472 
UpdateFunctionTable(const std::shared_ptr<Node> & node) const473 void panda::guard::Function::UpdateFunctionTable(const std::shared_ptr<Node> &node) const
474 {
475     if (this->idx_ == this->obfIdx_) {
476         return;
477     }
478     auto entry = this->program_->prog_->function_table.extract(this->idx_);
479     entry.key() = this->obfIdx_;
480     entry.mapped().name = this->obfIdx_;
481     if (node->fileNameNeedUpdate_ && !entry.mapped().source_file.empty()) {
482         node->UpdateSourceFile(entry.mapped().source_file);
483         entry.mapped().source_file = node->obfSourceFile_;
484     }
485     this->program_->prog_->function_table.insert(std::move(entry));
486 }
487 
GetGraph(compiler::Graph * & outGraph)488 void panda::guard::Function::GetGraph(compiler::Graph *&outGraph)
489 {
490     // the existence of graph_ depends on GraphContext
491     auto context = GuardContext::GetInstance()->GetGraphContext();
492     PANDA_GUARD_ASSERT_PRINT(context == nullptr, TAG, ErrorCode::GENERIC_ERROR, "graph context not inited");
493 
494     if (this->graph_ != nullptr) {
495         outGraph = this->graph_;
496         return;
497     }
498 
499     this->methodPtr_ = context->FillMethodPtr(this->recordName_, this->rawName_);
500     PANDA_GUARD_ASSERT_PRINT(this->methodPtr_ == 0, TAG, ErrorCode::GENERIC_ERROR,
501                              "can not find method ptr for: " << this->idx_);
502 
503     auto methodPtr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(this->methodPtr_);
504     this->allocator_ = std::make_unique<ArenaAllocator>(SpaceType::SPACE_TYPE_COMPILER);
505     this->localAllocator_ = std::make_unique<ArenaAllocator>(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
506     this->runtimeInterface_ = std::make_unique<panda::BytecodeOptimizerRuntimeAdapter>(context->GetAbcFile());
507     auto graph =
508         this->allocator_->New<compiler::Graph>(this->allocator_.get(), this->localAllocator_.get(), Arch::NONE,
509                                                methodPtr, this->runtimeInterface_.get(), false, nullptr, true, true);
510     PANDA_GUARD_ASSERT_PRINT((graph == nullptr) || !graph->RunPass<panda::compiler::IrBuilder>(), TAG,
511                              ErrorCode::GENERIC_ERROR, "Graph " << this->idx_ << ": IR builder failed!");
512 
513     this->BuildPcInsMap(graph);
514     this->graph_ = graph;
515     LOG(INFO, PANDAGUARD) << TAG << "create graph for " << this->idx_ << " end";
516 
517     outGraph = graph;
518 }
519 
BuildPcInsMap(const compiler::Graph * graph)520 void panda::guard::Function::BuildPcInsMap(const compiler::Graph *graph)
521 {
522     auto methodPtr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(this->methodPtr_);
523 
524     size_t funcSize = this->GetOriginFunction().ins.size();
525     this->pcInstMap_.reserve(funcSize);
526 
527     auto instructionsBuf = graph->GetRuntime()->GetMethodCode(methodPtr);
528     compiler::BytecodeInstructions instructions(instructionsBuf, graph->GetRuntime()->GetMethodCodeSize(methodPtr));
529     compiler::BytecodeIterator ins_iter = instructions.begin();
530 
531     for (size_t idx = 0; idx < this->GetOriginFunction().ins.size(); idx++) {
532         auto ins = this->GetOriginFunction().ins[idx].get();
533         if (ins->opcode == pandasm::Opcode::INVALID) {
534             continue;
535         }
536         this->pcInstMap_.emplace(instructions.GetPc(*ins_iter), idx);
537         ++ins_iter;
538         if (ins_iter == instructions.end()) {
539             break;
540         }
541     }
542 }
543 
FreeGraph()544 void panda::guard::Function::FreeGraph()
545 {
546     std::unordered_map<size_t, size_t>().swap(this->pcInstMap_);
547 
548     this->graph_ = nullptr;
549     this->localAllocator_ = nullptr;
550     this->runtimeInterface_ = nullptr;
551     this->allocator_ = nullptr;
552 }
553 
Update()554 void panda::guard::Function::Update()
555 {
556     LOG(INFO, PANDAGUARD) << TAG << "function update for " << this->idx_ << " start";
557 
558     auto it = this->program_->nodeTable_.find(this->recordName_);
559     PANDA_GUARD_ASSERT_PRINT(it == this->program_->nodeTable_.end(), TAG, ErrorCode::GENERIC_ERROR,
560                              "not find node: " + this->recordName_);
561 
562     this->UpdateName(it->second);
563     this->UpdateDefine();
564     this->UpdateFunctionTable(it->second);
565 
566     if (it->second->contentNeedUpdate_ && this->contentNeedUpdate_) {
567         for (const auto &[_, property] : this->propertyTable_) {
568             property->Obfuscate();
569         }
570     }
571 
572     for (const auto &property : this->variableProperties_) {
573         property->Obfuscate();
574     }
575 
576     if (GuardContext::GetInstance()->GetGuardOptions()->IsDecoratorObfEnabled()) {
577         for (const auto &property : this->objectDecoratorProperties_) {
578             property->Obfuscate();
579         }
580     }
581 
582     LOG(INFO, PANDAGUARD) << TAG << "function update for " << this->idx_ << " end";
583 }
584 
WriteNameCache(const std::string & filePath)585 void panda::guard::Function::WriteNameCache(const std::string &filePath)
586 {
587     if (IsNameObfuscated()) {
588         this->WriteFileCache(filePath);
589         this->WritePropertyCache();
590     }
591 
592     for (const auto &[_, property] : this->propertyTable_) {
593         property->WriteNameCache(filePath);
594     }
595 
596     for (const auto &property : this->variableProperties_) {
597         property->WritePropertyCache();
598     }
599 
600     if (GuardContext::GetInstance()->GetGuardOptions()->IsDecoratorObfEnabled()) {
601         for (const auto &property : this->objectDecoratorProperties_) {
602             property->WritePropertyCache();
603         }
604     }
605 }
606 
WriteFileCache(const std::string & filePath)607 void panda::guard::Function::WriteFileCache(const std::string &filePath)
608 {
609     if (this->type_ != panda::guard::FunctionType::CONSTRUCTOR_FUNCTION) {
610         std::string name = this->GetNameCacheScope();
611         if (this->type_ != panda::guard::FunctionType::ENUM_FUNCTION) {
612             name += this->GetLines();
613         }
614         GuardContext::GetInstance()->GetNameCache()->AddObfIdentifierName(filePath, name, this->obfName_);
615     } else {
616         std::string name = this->name_ + this->GetLines();
617         GuardContext::GetInstance()->GetNameCache()->AddObfMemberMethodName(filePath, name, this->obfName_);
618     }
619 }
620 
WritePropertyCache()621 void panda::guard::Function::WritePropertyCache()
622 {
623     TopLevelOptionEntity::WritePropertyCache(*this);
624 }
625 
IsNameObfuscated() const626 bool panda::guard::Function::IsNameObfuscated() const
627 {
628     return !IsWhiteListOrAnonymousFunction(this->idx_);
629 }
630