• 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 <algorithm>
17 #include <cassert>
18 #include <sstream>
19 #include "libabckit/include/c/abckit.h"
20 #include "api_scanner.h"
21 #include "helpers/helpers.h"
22 
ApiScanner(enum AbckitApiVersion version,AbckitFile * file,std::vector<ApiInfo> apiList)23 ApiScanner::ApiScanner(enum AbckitApiVersion version, AbckitFile *file, std::vector<ApiInfo> apiList)
24     : file_(file), apiList_(std::move(apiList))
25 {
26     impl_ = AbckitGetApiImpl(version);
27     implI_ = AbckitGetInspectApiImpl(version);
28     implG_ = AbckitGetGraphApiImpl(version);
29     dynG_ = AbckitGetIsaApiDynamicImpl(version);
30     vh_ = VisitHelper(file_, impl_, implI_, implG_, dynG_);
31 }
32 
CollectApiUsages()33 void ApiScanner::CollectApiUsages()
34 {
35     vh_.EnumerateModules([&](AbckitCoreModule *mod) {
36         SuspectsMap suspects;
37         GetSuspects(mod, suspects);
38         if (suspects.empty()) {
39             return;
40         }
41         vh_.EnumerateModuleFunctions(mod, [&](AbckitCoreFunction *method) { CollectUsageInMethod(method, suspects); });
42     });
43 }
44 
GetSuspects(AbckitCoreModule * mod,SuspectsMap & suspects)45 bool ApiScanner::GetSuspects(AbckitCoreModule *mod, SuspectsMap &suspects)
46 {
47     vh_.EnumerateModuleImports(mod, [&](AbckitCoreImportDescriptor *id) {
48         auto importName = vh_.GetString(implI_->importDescriptorGetName(id));
49         auto *importedModule = implI_->importDescriptorGetImportedModule(id);
50         auto source = vh_.GetString(implI_->moduleGetName(importedModule));
51         for (size_t i = 0; i < apiList_.size(); ++i) {
52             const auto api = apiList_[i];
53             if (source != api.source) {
54                 continue;
55             }
56             if (importName == api.objName) {
57                 suspects.emplace(id, i);
58             }
59         }
60     });
61     return !suspects.empty();
62 }
63 
IsLoadApi(AbckitCoreImportDescriptor * id,size_t apiIndex,AbckitInst * inst)64 bool ApiScanner::IsLoadApi(AbckitCoreImportDescriptor *id, size_t apiIndex, AbckitInst *inst)
65 {
66     // find the following pattern:
67     // 1. ldExternalModuleVar (import {ApiNamespace} from "./modules/myApi")
68     // 2. ldObjByName v1, "foo" (api.propName)
69     // or
70     // 1. ldExternalModuleVar (import {bar} from "./modules/myApi")
71 
72     if (dynG_->iGetOpcode(inst) != ABCKIT_ISA_API_DYNAMIC_OPCODE_LDEXTERNALMODULEVAR) {
73         return false;
74     }
75 
76     if (dynG_->iGetImportDescriptor(inst) != id) {
77         return false;
78     }
79 
80     const auto &prop = apiList_[apiIndex].propName;
81     if (prop.empty()) {
82         return true;
83     }
84 
85     bool found = false;
86     vh_.EnumerateInstUsers(inst, [&](AbckitInst *user) {
87         if (!found && dynG_->iGetOpcode(user) == ABCKIT_ISA_API_DYNAMIC_OPCODE_LDOBJBYNAME) {
88             auto str = vh_.GetString(implG_->iGetString(user));
89             found = str == prop;
90         }
91     });
92 
93     return found;
94 }
95 
GetMethodName(AbckitCoreFunction * method)96 std::string ApiScanner::GetMethodName(AbckitCoreFunction *method)
97 {
98     auto mname = implI_->functionGetName(method);
99     auto methodName = std::string(libabckit::test::helpers::AbckitStringToString(mname));
100     auto *cls = implI_->functionGetParentClass(method);
101     if (cls == nullptr) {
102         return methodName;
103     }
104     auto cname = implI_->classGetName(cls);
105     auto className = std::string(libabckit::test::helpers::AbckitStringToString(cname));
106     return className + '.' + methodName;
107 }
108 
CollectUsageInMethod(AbckitCoreFunction * method,SuspectsMap & suspects)109 void ApiScanner::CollectUsageInMethod(AbckitCoreFunction *method, SuspectsMap &suspects)
110 {
111     auto methodName = GetMethodName(method);
112     auto *sourceRaw = implI_->moduleGetName(implI_->functionGetModule(method));
113     auto source = vh_.GetString(sourceRaw);
114     UsageInfo usage = {source.data(), methodName, 0};
115     vh_.EnumerateFunctionInsts(method, [&](AbckitInst *inst) {
116         for (const auto &[id, apiIndex] : suspects) {
117             if (IsLoadApi(id, apiIndex, inst)) {
118                 usage.idx = apiIndex;
119                 AddApiUsage(apiIndex, usage);
120             }
121         }
122     });
123 }
124 
GetQuatatedStr(const std::string & str)125 static std::string GetQuatatedStr(const std::string &str)
126 {
127     const static std::string QUOTATION = "\"";
128     return QUOTATION + str + QUOTATION;
129 }
130 
ApiUsageMapGetString() const131 std::string ApiScanner::ApiUsageMapGetString() const
132 {
133     std::stringstream ss;
134     const static std::string INDENT_1 = "  ";
135     const static std::string INDENT_2 = INDENT_1 + INDENT_1;
136     const static std::string INDENT_3 = INDENT_1 + INDENT_2;
137     const static std::string INDENT_4 = INDENT_1 + INDENT_3;
138     const static std::string LEFT_BRACKET = "{";
139     const static std::string RIGHT_BRACKET = "}";
140     const static std::string COLON = ": ";
141     const static std::string COMMA = ",";
142     const static std::string APIINFO = "APIInfo";
143     const static std::string APIINFO_SOURCE = "source";
144     const static std::string APIINFO_OBJNAME = "objName";
145     const static std::string APIINFO_PROPNAME = "propName";
146     const static std::string USAGES = "Usages";
147     const static std::string USAGES_SOURCE = "source";
148     const static std::string USAGES_FUNCNAME = "funcName";
149     const static std::string API_IDX = "indexOfAPI";
150 
151     LIBABCKIT_LOG(DEBUG) << LEFT_BRACKET << std::endl;
152     for (const auto &[index, usageInfos] : apiUsages_) {
153         LIBABCKIT_LOG(DEBUG) << INDENT_1 << LEFT_BRACKET << std::endl;
154 
155         if (usageInfos.empty()) {
156             continue;
157         }
158         const auto &apiInfo = apiList_[index];
159         LIBABCKIT_LOG(DEBUG) << INDENT_2 << APIINFO << COLON << LEFT_BRACKET << std::endl;
160         LIBABCKIT_LOG(DEBUG) << INDENT_3 << APIINFO_SOURCE << COLON << GetQuatatedStr(apiInfo.source) << COMMA
161                              << std::endl;
162         LIBABCKIT_LOG(DEBUG) << INDENT_3 << APIINFO_OBJNAME << COLON << GetQuatatedStr(apiInfo.objName) << COMMA
163                              << std::endl;
164         LIBABCKIT_LOG(DEBUG) << INDENT_3 << APIINFO_PROPNAME << COLON << GetQuatatedStr(apiInfo.propName) << COMMA
165                              << std::endl;
166         LIBABCKIT_LOG(DEBUG) << INDENT_2 << RIGHT_BRACKET << COMMA << std::endl;
167 
168         LIBABCKIT_LOG(DEBUG) << INDENT_2 << USAGES << COLON << LEFT_BRACKET << std::endl;
169         for (const auto &usage : usageInfos) {
170             LIBABCKIT_LOG(DEBUG) << INDENT_3 << LEFT_BRACKET << std::endl;
171             LIBABCKIT_LOG(DEBUG) << INDENT_4 << USAGES_SOURCE << COLON << GetQuatatedStr(usage.source) << COMMA
172                                  << std::endl;
173             LIBABCKIT_LOG(DEBUG) << INDENT_4 << USAGES_FUNCNAME << COLON << GetQuatatedStr(usage.funcName) << COMMA
174                                  << std::endl;
175             LIBABCKIT_LOG(DEBUG) << INDENT_4 << API_IDX << COLON << usage.idx << COMMA << std::endl;
176             LIBABCKIT_LOG(DEBUG) << INDENT_3 << RIGHT_BRACKET << COMMA << std::endl;
177         }
178         LIBABCKIT_LOG(DEBUG) << INDENT_2 << RIGHT_BRACKET << std::endl;
179 
180         LIBABCKIT_LOG(DEBUG) << INDENT_1 << RIGHT_BRACKET << COMMA << std::endl;
181     }
182     LIBABCKIT_LOG(DEBUG) << RIGHT_BRACKET << std::endl;
183 
184     return ss.str();
185 }
186 
IsUsagesEqual(const std::vector<UsageInfo> & otherUsages) const187 bool ApiScanner::IsUsagesEqual(const std::vector<UsageInfo> &otherUsages) const
188 {
189     for (auto &otherUsage : otherUsages) {
190         auto usages = apiUsages_.at(otherUsage.idx);
191         auto iter = std::find_if(usages.begin(), usages.end(), [&otherUsage](const UsageInfo &usage) {
192             return (otherUsage.funcName == usage.funcName) && (otherUsage.source == usage.source) &&
193                    (otherUsage.idx == usage.idx);
194         });
195         if (iter == usages.end()) {
196             return false;
197         }
198     }
199     return true;
200 }
201