• 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 constexpr size_t STOBJBYVALUE_ACC_INDEX = 2;
44 
45 const std::map<char, panda::guard::FunctionType> FUNCTION_TYPE_MAP = {
46     {'>', panda::guard::FunctionType::INSTANCE_FUNCTION},    {'<', panda::guard::FunctionType::STATIC_FUNCTION},
47     {'=', panda::guard::FunctionType::CONSTRUCTOR_FUNCTION}, {'*', panda::guard::FunctionType::NORMAL_FUNCTION},
48     {'%', panda::guard::FunctionType::ENUM_FUNCTION},        {'&', panda::guard::FunctionType::NAMESPACE_FUNCTION},
49 };
50 
51 /**
52  * Is it an entry function (func_main_0)
53  * @param functionIdx function Idx
54  * @return (true/false)
55  */
IsEntryMethod(const std::string & functionIdx)56 bool IsEntryMethod(const std::string &functionIdx)
57 {
58     return functionIdx.find(ENTRY_FUNC_TAG) != std::string::npos;
59 }
60 
61 /**
62  * Is it an implicit function (dynamically generated in bytecode, not reflected in source code)
63  * @param functionIdx function Idx
64  * @return (true/false)
65  */
IsImplicitMethod(const std::string & functionIdx)66 bool IsImplicitMethod(const std::string &functionIdx)
67 {
68     return functionIdx.find(INSTANCE_INITIALIZER_TAG) != std::string::npos ||
69            functionIdx.find(STATIC_INITIALIZER_TAG) != std::string::npos;
70 }
71 
72 /**
73  * Do not obfuscate the names of whitelist functions (internal instructions and associated properties need to be
74  * obfuscated)
75  * @param functionIdx function Idx
76  * @return (true/false)
77  */
IsWhiteListFunction(const std::string & functionIdx)78 bool IsWhiteListFunction(const std::string &functionIdx)
79 {
80     return IsEntryMethod(functionIdx) || IsImplicitMethod(functionIdx);
81 }
82 
GetConsoleLogInfoForStart(const std::vector<panda::pandasm::Ins> & insList,size_t & start,uint16_t & reg)83 bool GetConsoleLogInfoForStart(const std::vector<panda::pandasm::Ins> &insList, size_t &start, uint16_t &reg)
84 {
85     size_t i = 0;
86     while (i < insList.size()) {
87         auto &ins = insList[i];
88         if (ins.opcode == panda::pandasm::Opcode::TRYLDGLOBALBYNAME && ins.ids[0] == CONSOLE_INS_VAR) {
89             size_t nextInsIndex = i + 1;
90             PANDA_GUARD_ASSERT_PRINT(nextInsIndex >= insList.size(), TAG, panda::guard::ErrorCode::GENERIC_ERROR,
91                                      "get console next ins get bad index:" << nextInsIndex);
92 
93             auto &nextIns = insList[nextInsIndex];
94             PANDA_GUARD_ASSERT_PRINT(nextIns.opcode != panda::pandasm::Opcode::STA, TAG,
95                                      panda::guard::ErrorCode::GENERIC_ERROR, "get console next ins get bad ins type");
96 
97             reg = nextIns.regs[0];
98             start = i;
99             return true;
100         }
101         i++;
102     }
103 
104     return false;
105 }
106 
HasMovInstForRange(const std::vector<panda::pandasm::Ins> & insList,size_t start,size_t end,uint16_t oriReg,uint16_t rangeReg)107 bool HasMovInstForRange(const std::vector<panda::pandasm::Ins> &insList, size_t start, size_t end, uint16_t oriReg,
108                         uint16_t rangeReg)
109 {
110     size_t i = end - 1;
111     while (i > start) {
112         auto &ins = insList[i];
113         if ((ins.opcode == panda::pandasm::Opcode::MOV) && (ins.regs[0] == rangeReg) && (ins.regs[1] == oriReg)) {
114             return true;
115         }
116         i--;
117     }
118     return false;
119 }
120 
GetConsoleLogInfoForEnd(const std::vector<panda::pandasm::Ins> & insList,size_t start,uint16_t reg,size_t & end)121 int GetConsoleLogInfoForEnd(const std::vector<panda::pandasm::Ins> &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.regs[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.regs[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::Ins> & insList,size_t & start,size_t & end)152 bool GetConsoleLogInfo(const std::vector<panda::pandasm::Ins> &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 
ReplaceJumpInsLabel(std::vector<panda::pandasm::Ins> & insList,const std::string & oldLabel,const std::string & newLabel)171 void ReplaceJumpInsLabel(std::vector<panda::pandasm::Ins> &insList, const std::string &oldLabel,
172                          const std::string &newLabel)
173 {
174     size_t i = 0;
175     while (i < insList.size()) {
176         auto &ins = insList[i];
177         if (!ins.ids.empty() && ins.ids[0] == oldLabel) {
178             ins.ids[0] = newLabel;
179             LOG(INFO, PANDAGUARD) << TAG << "replace label at index:" << i << " " << oldLabel << "-->" << newLabel;
180         }
181         i++;
182     }
183 }
184 }  // namespace
185 
Init()186 void panda::guard::Function::Init()
187 {
188     /* e.g.
189      * idx_: &entry/src/main/ets/entryability/EntryAbility&.#~@0>#onCreate
190      * recordName_: &entry/src/main/ets/entryability/EntryAbility&
191      * rawName_: #~@0>#onCreate
192      * scopeTypeStr_: ~@0>
193      */
194     LOG(INFO, PANDAGUARD) << TAG << "Function:" << this->idx_;
195     this->obfIdx_ = this->idx_;
196     const auto &[recordName, rawName] = StringUtil::RSplitOnce(this->idx_, RECORD_DELIMITER.data());
197     PANDA_GUARD_ASSERT_PRINT(recordName.empty() || rawName.empty(), TAG, ErrorCode::GENERIC_ERROR,
198                              "split record and name get bad value");
199 
200     this->recordName_ = recordName;
201     this->rawName_ = rawName;
202 
203     this->InitBaseInfo();
204 
205     LOG(INFO, PANDAGUARD) << TAG << "idx:" << this->idx_;
206     LOG(INFO, PANDAGUARD) << TAG << "recordName:" << this->recordName_;
207     LOG(INFO, PANDAGUARD) << TAG << "rawName:" << this->rawName_;
208     LOG(INFO, PANDAGUARD) << TAG << "regsNum:" << this->regsNum;
209     LOG(INFO, PANDAGUARD) << TAG << "startLine:" << this->startLine_;
210     LOG(INFO, PANDAGUARD) << TAG << "endLine:" << this->endLine_;
211 
212     if (!this->useScope_) {
213         return;
214     }
215 
216     std::vector<std::string> scopeAndName = StringUtil::Split(rawName, SCOPE_DELIMITER.data());
217     PANDA_GUARD_ASSERT_PRINT(scopeAndName.empty() || scopeAndName.size() > SCOPE_AND_NAME_LEN, TAG,
218                              ErrorCode::GENERIC_ERROR, "split scope and name get bad len");
219 
220     this->scopeTypeStr_ = scopeAndName[0];
221     this->SetFunctionType(scopeAndName[0].back());
222     this->name_ = scopeAndName.size() > 1 ? scopeAndName[1] : ANONYMOUS_FUNCTION_NAME;
223 
224     if (StringUtil::IsAnonymousFunctionName(this->name_)) {
225         this->anonymous = true;
226     }
227 
228     this->obfName_ = this->name_;
229 
230     LOG(INFO, PANDAGUARD) << TAG << "scopeTypeStr:" << this->scopeTypeStr_;
231     LOG(INFO, PANDAGUARD) << TAG << "type:" << (int)this->type_;
232     LOG(INFO, PANDAGUARD) << TAG << "name:" << this->name_;
233     LOG(INFO, PANDAGUARD) << TAG << "anonymous:" << (this->anonymous ? "true" : "false");
234 }
235 
GetOriginFunction()236 panda::pandasm::Function &panda::guard::Function::GetOriginFunction()
237 {
238     return this->program_->prog_->function_table.at(this->obfIdx_);
239 }
240 
InitBaseInfo()241 void panda::guard::Function::InitBaseInfo()
242 {
243     const auto &func = this->GetOriginFunction();
244     this->name_ = this->idx_;
245     this->obfName_ = this->name_;
246     this->regsNum = func.regs_num;
247 
248     size_t startLineIndex = 0;
249     while (startLineIndex < func.ins.size()) {
250         const size_t lineNumber = func.ins[startLineIndex].ins_debug.line_number;
251         if (lineNumber < MAX_LINE_NUMBER) {
252             this->startLine_ = lineNumber;
253             break;
254         }
255         startLineIndex++;
256     }
257 
258     size_t endLineIndex = func.ins.size() - 1;
259     while (endLineIndex >= startLineIndex) {
260         const size_t lineNumber = func.ins[endLineIndex].ins_debug.line_number;
261         if (lineNumber < MAX_LINE_NUMBER) {
262             this->endLine_ = lineNumber + 1;
263             break;
264         }
265         endLineIndex--;
266     }
267 }
268 
SetFunctionType(char functionTypeCode)269 void panda::guard::Function::SetFunctionType(char functionTypeCode)
270 {
271     PANDA_GUARD_ASSERT_PRINT(FUNCTION_TYPE_MAP.find(functionTypeCode) == FUNCTION_TYPE_MAP.end(), TAG,
272                              ErrorCode::GENERIC_ERROR, "unsupported function type code:" << functionTypeCode);
273 
274     this->type_ = FUNCTION_TYPE_MAP.at(functionTypeCode);
275 }
276 
InitNameCacheScope()277 void panda::guard::Function::InitNameCacheScope()
278 {
279     this->SetNameCacheScope(this->name_);
280 }
281 
Build()282 void panda::guard::Function::Build()
283 {
284     if (IsEntryMethod(this->idx_)) {
285         return;
286     }
287 
288     LOG(INFO, PANDAGUARD) << TAG << "function build for " << this->idx_ << " start";
289 
290     this->InitNameCacheScope();
291 
292     this->ForEachIns([&](const InstructionInfo &info) -> void { CreateProperty(info); });
293 
294     LOG(INFO, PANDAGUARD) << TAG << "scope:" << (this->scope_ == TOP_LEVEL ? "TOP_LEVEL" : "Function");
295     LOG(INFO, PANDAGUARD) << TAG << "nameCacheScope:" << this->GetNameCacheScope();
296     LOG(INFO, PANDAGUARD) << TAG << "export:" << (this->export_ ? "true" : "false");
297     LOG(INFO, PANDAGUARD) << TAG << "propertiesSize:" << this->properties_.size();
298 
299     LOG(INFO, PANDAGUARD) << TAG << "function build for " << this->idx_ << " end";
300 }
301 
IsWhiteListOrAnonymousFunction(const std::string & functionIdx) const302 bool panda::guard::Function::IsWhiteListOrAnonymousFunction(const std::string &functionIdx) const
303 {
304     return IsWhiteListFunction(functionIdx) || this->anonymous;
305 }
306 
RefreshNeedUpdate()307 void panda::guard::Function::RefreshNeedUpdate()
308 {
309     this->needUpdate = true;
310     this->contentNeedUpdate_ = true;
311     this->nameNeedUpdate_ = TopLevelOptionEntity::NeedUpdate(*this) && !IsWhiteListOrAnonymousFunction(this->idx_);
312     LOG(INFO, PANDAGUARD) << TAG << "Function nameNeedUpdate: " << (this->nameNeedUpdate_ ? "true" : "false");
313 }
314 
ForEachIns(const std::function<InsTraver> & callback)315 void panda::guard::Function::ForEachIns(const std::function<InsTraver> &callback)
316 {
317     auto &func = this->GetOriginFunction();
318     for (size_t i = 0; i < func.ins.size(); i++) {
319         InstructionInfo info(this, &func.ins[i], i);
320         callback(info);
321     }
322 }
323 
UpdateReference()324 void panda::guard::Function::UpdateReference()
325 {
326     if (IsImplicitMethod(this->idx_)) {
327         LOG(INFO, PANDAGUARD) << TAG << "skip update reference for:" << this->idx_;
328         return;
329     }
330 
331     LOG(INFO, PANDAGUARD) << TAG << "update reference start:" << this->idx_;
332     this->ForEachIns([&](InstructionInfo &info) -> void { InstObf::UpdateInst(info); });
333     LOG(INFO, PANDAGUARD) << TAG << "update reference end:" << this->idx_;
334 }
335 
RemoveConsoleLog()336 void panda::guard::Function::RemoveConsoleLog()
337 {
338     auto &insList = this->GetOriginFunction().ins;
339     size_t start = 0;
340     size_t end = 0;
341     while (GetConsoleLogInfo(insList, start, end)) {
342         LOG(INFO, PANDAGUARD) << TAG << "remove console log for:" << this->idx_;
343         LOG(INFO, PANDAGUARD) << TAG << "found console ins range:[" << start << ", " << end << ")";
344         PANDA_GUARD_ASSERT_PRINT(end >= insList.size(), TAG, ErrorCode::GENERIC_ERROR,
345                                  "bad end ins index for console:" << end);
346         if (insList[start].set_label) {
347             if (insList[end].set_label) {
348                 // replace jump ins label
349                 ReplaceJumpInsLabel(insList, insList[start].label, insList[end].label);
350             } else {
351                 // add label to end ins
352                 insList[end].set_label = true;
353                 insList[end].label = insList[start].label;
354             }
355         }
356         insList.erase(insList.begin() + start, insList.begin() + end);
357     }
358 }
359 
FillInstInfo(size_t index,InstructionInfo & instInfo)360 void panda::guard::Function::FillInstInfo(size_t index, InstructionInfo &instInfo)
361 {
362     auto &func = this->GetOriginFunction();
363     PANDA_GUARD_ASSERT_PRINT(index >= func.ins.size(), TAG, ErrorCode::GENERIC_ERROR, "out of range index: " << index);
364 
365     instInfo.index_ = index;
366     instInfo.ins_ = &func.ins[index];
367     instInfo.function_ = this;
368 }
369 
ExtractNames(std::set<std::string> & strings) const370 void panda::guard::Function::ExtractNames(std::set<std::string> &strings) const
371 {
372     strings.emplace(this->name_);
373     for (const auto &property : this->properties_) {
374         property.ExtractNames(strings);
375     }
376 }
377 
GetLines() const378 std::string panda::guard::Function::GetLines() const
379 {
380     return LINE_DELIMITER.data() + std::to_string(this->startLine_) + LINE_DELIMITER.data() +
381            std::to_string(this->endLine_);
382 }
383 
CreateProperty(const InstructionInfo & info)384 void panda::guard::Function::CreateProperty(const InstructionInfo &info)
385 {
386     if (!Property::IsPropertyIns(info)) {
387         return;
388     }
389 
390     InstructionInfo nameInfo;
391     Property::GetPropertyNameInfo(info, nameInfo);
392     // if function is enum function, try to find property in acc
393     if (!nameInfo.IsValid() && this->type_ == FunctionType::ENUM_FUNCTION) {
394         // e.g. this[0] = 'property'
395         LOG(INFO, PANDAGUARD) << TAG << "try to find property in acc";
396         GraphAnalyzer::GetLdaStr(info, nameInfo, STOBJBYVALUE_ACC_INDEX);
397     }
398 
399     if (!nameInfo.IsValid()) {
400         LOG(INFO, PANDAGUARD) << TAG << "invalid nameInfo:" << info.index_ << " " << info.ins_->ToString();
401         return;
402     }
403 
404     std::string name = StringUtil::UnicodeEscape(nameInfo.ins_->ids[0]);
405     Property property(this->program_, name);
406     property.defineInsList_.push_back(info);
407     property.nameInfo_ = nameInfo;
408     if (!info.IsInnerReg()) {
409         property.scope_ = this->scope_;
410         property.export_ = this->export_;
411         property.Create();
412 
413         LOG(INFO, PANDAGUARD) << TAG << "find property:" << property.name_;
414 
415         this->properties_.push_back(property);
416     } else {
417         property.scope_ = FUNCTION;
418         property.export_ = false;
419         property.Create();
420 
421         LOG(INFO, PANDAGUARD) << TAG << "find variable property:" << property.name_;
422 
423         this->variableProperties_.push_back(property);
424     }
425 }
426 
UpdateName(const Node & node)427 void panda::guard::Function::UpdateName(const Node &node)
428 {
429     std::string obfRawName;
430     // The judgment here cannot be moved to the outer layer. The function here should not only confuse its own name, but
431     // also the file name Even if the file is kept, The function name may also be modified due to file name confusion,
432     // and the related logic still needs to be executed by the function itself
433     if (node.contentNeedUpdate_ && this->nameNeedUpdate_) {
434         /* e.g.
435          * #~@0=#EntryAbility
436          *  name_: EntryAbility
437          *  scopeTypeStr_: ~@0=
438          *  obfName_: a
439          *  obfRawName: #~@0=#a
440          */
441         this->obfName_ = GuardContext::GetInstance()->GetNameMapping()->GetName(this->name_);
442         obfRawName = SCOPE_DELIMITER.data() + this->scopeTypeStr_ + SCOPE_DELIMITER.data() + this->obfName_;
443     } else {
444         // e.g. rawName_: #~@0>@1*#
445         obfRawName = this->rawName_;
446     }
447 
448     this->obfIdx_ = node.obfName_ + RECORD_DELIMITER.data() + obfRawName;
449 }
450 
UpdateDefine() const451 void panda::guard::Function::UpdateDefine() const
452 {
453     bool obfuscated = false;
454 
455     for (auto &defineIns : this->defineInsList_) {
456         if (!defineIns.IsValid()) {
457             LOG(INFO, PANDAGUARD) << TAG << "no bind define ins, ignore update define";
458             continue;
459         }
460 
461         // definefunc, definemethod for function, defineclasswithbuffer, callruntime.definesendableclass for constructor
462         PANDA_GUARD_ASSERT_PRINT(defineIns.ins_->opcode != pandasm::Opcode::DEFINEFUNC &&
463                                      defineIns.ins_->opcode != pandasm::Opcode::DEFINECLASSWITHBUFFER &&
464                                      defineIns.ins_->opcode != pandasm::Opcode::CALLRUNTIME_DEFINESENDABLECLASS &&
465                                      defineIns.ins_->opcode != pandasm::Opcode::DEFINEMETHOD,
466                                  TAG, ErrorCode::GENERIC_ERROR, "get bad ins type");
467 
468         defineIns.ins_->ids[0] = this->obfIdx_;
469         obfuscated = true;
470     }
471 
472     if (obfuscated) {
473         this->program_->prog_->strings.emplace(this->obfIdx_);
474     }
475 }
476 
UpdateFunctionTable(Node & node)477 void panda::guard::Function::UpdateFunctionTable(Node &node)
478 {
479     if (this->idx_ == this->obfIdx_) {
480         return;
481     }
482     auto entry = this->program_->prog_->function_table.extract(this->idx_);
483     entry.key() = this->obfIdx_;
484     entry.mapped().name = this->obfIdx_;
485     if (node.fileNameNeedUpdate_ && !entry.mapped().source_file.empty()) {
486         node.UpdateSourceFile(entry.mapped().source_file);
487         entry.mapped().source_file = node.obfSourceFile_;
488     }
489     this->program_->prog_->function_table.insert(std::move(entry));
490 }
491 
GetGraph(compiler::Graph * & outGraph)492 void panda::guard::Function::GetGraph(compiler::Graph *&outGraph)
493 {
494     // the existence of graph_ depends on GraphContext
495     auto context = GuardContext::GetInstance()->GetGraphContext();
496     PANDA_GUARD_ASSERT_PRINT(context == nullptr, TAG, ErrorCode::GENERIC_ERROR, "graph context not inited");
497 
498     if (this->graph_ != nullptr) {
499         outGraph = this->graph_;
500         return;
501     }
502 
503     this->methodPtr_ = context->FillMethodPtr(this->recordName_, this->rawName_);
504     PANDA_GUARD_ASSERT_PRINT(this->methodPtr_ == 0, TAG, ErrorCode::GENERIC_ERROR,
505                              "can not find method ptr for: " << this->idx_);
506 
507     auto methodPtr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(this->methodPtr_);
508     this->allocator_ = std::make_shared<ArenaAllocator>(SpaceType::SPACE_TYPE_COMPILER);
509     this->localAllocator_ = std::make_shared<ArenaAllocator>(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
510     this->runtimeInterface_ = std::make_shared<panda::BytecodeOptimizerRuntimeAdapter>(context->GetAbcFile());
511     auto graph =
512         this->allocator_->New<compiler::Graph>(this->allocator_.get(), this->localAllocator_.get(), Arch::NONE,
513                                                methodPtr, this->runtimeInterface_.get(), false, nullptr, true, true);
514     PANDA_GUARD_ASSERT_PRINT((graph == nullptr) || !graph->RunPass<panda::compiler::IrBuilder>(), TAG,
515                              ErrorCode::GENERIC_ERROR, "Graph " << this->idx_ << ": IR builder failed!");
516 
517     this->BuildPcInsMap(graph);
518     this->graph_ = graph;
519     LOG(INFO, PANDAGUARD) << TAG << "create graph for " << this->idx_ << " end";
520 
521     outGraph = graph;
522 }
523 
BuildPcInsMap(const compiler::Graph * graph)524 void panda::guard::Function::BuildPcInsMap(const compiler::Graph *graph)
525 {
526     auto methodPtr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(this->methodPtr_);
527 
528     size_t funcSize = this->GetOriginFunction().ins.size();
529     this->pcInstMap_.reserve(funcSize);
530 
531     auto instructionsBuf = graph->GetRuntime()->GetMethodCode(methodPtr);
532     compiler::BytecodeInstructions instructions(instructionsBuf, graph->GetRuntime()->GetMethodCodeSize(methodPtr));
533     size_t idx = 0;
534     for (auto inst : instructions) {
535         this->pcInstMap_.emplace(instructions.GetPc(inst), idx);
536         idx++;
537         if (idx >= funcSize) {
538             break;
539         }
540     }
541 }
542 
Update()543 void panda::guard::Function::Update()
544 {
545     LOG(INFO, PANDAGUARD) << TAG << "function update for " << this->idx_ << " start";
546 
547     auto it = this->program_->nodeTable_.find(this->recordName_);
548     PANDA_GUARD_ASSERT_PRINT(it == this->program_->nodeTable_.end(), TAG, ErrorCode::GENERIC_ERROR,
549                              "not find node: " + this->recordName_);
550 
551     this->UpdateName(it->second);
552     this->UpdateDefine();
553     this->UpdateFunctionTable(it->second);
554 
555     if (it->second.contentNeedUpdate_ && this->contentNeedUpdate_) {
556         for (auto &property : this->properties_) {
557             property.Obfuscate();
558         }
559     }
560 
561     for (auto &property : this->variableProperties_) {
562         property.Obfuscate();
563     }
564 
565     LOG(INFO, PANDAGUARD) << TAG << "function update for " << this->idx_ << " end";
566 }
567 
WriteNameCache(const std::string & filePath)568 void panda::guard::Function::WriteNameCache(const std::string &filePath)
569 {
570     if (IsNameObfuscated()) {
571         this->WriteFileCache(filePath);
572         this->WritePropertyCache();
573     }
574 
575     for (auto &property : this->properties_) {
576         property.WriteNameCache(filePath);
577     }
578 
579     for (auto &property : this->variableProperties_) {
580         property.WritePropertyCache();
581     }
582 }
583 
WriteFileCache(const std::string & filePath)584 void panda::guard::Function::WriteFileCache(const std::string &filePath)
585 {
586     if (this->type_ != panda::guard::FunctionType::CONSTRUCTOR_FUNCTION) {
587         std::string name = this->GetNameCacheScope();
588         if (this->type_ != panda::guard::FunctionType::ENUM_FUNCTION) {
589             name += this->GetLines();
590         }
591         GuardContext::GetInstance()->GetNameCache()->AddObfIdentifierName(filePath, name, this->obfName_);
592     } else {
593         std::string name = this->name_ + this->GetLines();
594         GuardContext::GetInstance()->GetNameCache()->AddObfMemberMethodName(filePath, name, this->obfName_);
595     }
596 }
597 
WritePropertyCache()598 void panda::guard::Function::WritePropertyCache()
599 {
600     TopLevelOptionEntity::WritePropertyCache(*this);
601 }
602 
IsNameObfuscated() const603 bool panda::guard::Function::IsNameObfuscated() const
604 {
605     return !IsWhiteListOrAnonymousFunction(this->idx_);
606 }
607