• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 #include "hiperf_libreport.h"
16 
17 #if !is_ohos
18 // this is not good enough
19 #include <../musl/include/elf.h>
20 #endif
21 
22 #include "debug_logger.h"
23 #include "elf_parser.h"
24 #include "perf_file_reader.h"
25 #include "subcommand_dump.h"
26 #include "subcommand_report.h"
27 #include "utilities.h"
28 
29 using namespace OHOS::Developtools::HiPerf;
30 using namespace OHOS::Developtools::HiPerf::ELF;
31 extern "C" {
32 // this is a demo function
EchoLoopBack(const char * echo)33 const char *EchoLoopBack(const char *echo)
34 {
35     HLOGD("EchoLoopBack:%s\n", echo);
36     return echo;
37 }
38 
SetDebug(bool enable)39 int SetDebug(bool enable)
40 {
41 #ifdef HIPERF_DEBUG
42     if (enable) {
43         DebugLogger::GetInstance()->SetLogLevel(LEVEL_VERBOSE);
44         DebugLogger::GetInstance()->Disable(false);
45     } else {
46         DebugLogger::GetInstance()->Disable(true);
47     }
48 #endif
49     return 0;
50 }
51 
Report(const char * perfFile,const char * reportFile,const char * reportOptions)52 int Report(const char *perfFile, const char *reportFile, const char *reportOptions)
53 {
54     std::unique_ptr<SubCommandReport> report = std::make_unique<SubCommandReport>();
55     HLOGD("report the file %s to %s\n", perfFile, reportFile);
56     if (perfFile != nullptr and reportFile != nullptr) {
57         std::vector<std::string> args;
58         args.emplace_back("-i");
59         args.emplace_back(perfFile);
60         args.emplace_back("-o");
61         args.emplace_back(reportFile);
62         if (reportOptions != nullptr) {
63             std::vector<std::string> options = StringSplit(reportOptions);
64             for (std::string &option : options) {
65                 args.emplace_back(option);
66             }
67         }
68         if (report->ParseOption(args)) {
69             return report->OnSubCommand(args) ? 0 : -1;
70         }
71     } else {
72         printf("path is nullptr\n");
73     }
74     return -1;
75 }
76 
ReportJson(const char * perfFile,const char * reportFile)77 int ReportJson(const char *perfFile, const char *reportFile)
78 {
79     return ReportUnwindJson(perfFile, reportFile, nullptr);
80 }
81 
ReportUnwindJson(const char * perfFile,const char * reportFile,const char * symbolsDir)82 int ReportUnwindJson(const char *perfFile, const char *reportFile, const char *symbolsDir)
83 {
84     std::unique_ptr<SubCommandReport> report = std::make_unique<SubCommandReport>();
85     HLOGD("report the file %s to json file %s symbols from %s\n", perfFile, reportFile, symbolsDir);
86     if (perfFile != nullptr and reportFile != nullptr) {
87         std::vector<std::string> args;
88         args.emplace_back("-i");
89         args.emplace_back(perfFile);
90         args.emplace_back("-o");
91         args.emplace_back(reportFile);
92         args.emplace_back("--json");
93         if (symbolsDir != nullptr) {
94             args.emplace_back("--symbol-dir");
95             args.emplace_back(symbolsDir);
96         }
97         if (report->ParseOption(args)) {
98             return report->OnSubCommand(args) ? 0 : -1;
99         }
100     }
101     return -1;
102 }
103 
GetReader(const std::string & fileName)104 static std::unique_ptr<PerfFileReader> GetReader(const std::string &fileName)
105 {
106     // check if file exist
107     if (access(fileName.c_str(), F_OK) != 0) {
108         // file not exists
109         printf("Can not access data file %s\n", fileName.c_str());
110         return nullptr;
111     }
112 
113     auto reader = PerfFileReader::Instance(fileName);
114     if (reader == nullptr) {
115         printf("%s format not correct\n", fileName.c_str());
116         return nullptr;
117     } else {
118         return reader;
119     }
120 }
121 
ReportGetSymbolFiles(const char * perfFile)122 const char *ReportGetSymbolFiles(const char *perfFile)
123 {
124     HLOGD("report the file %s for symbols \n", perfFile);
125     static std::string result; // statci for hold the c_str buffer
126     result.clear();
127     if (perfFile == nullptr) {
128         return result.c_str();
129     }
130 
131     auto reader = GetReader(perfFile);
132     if (reader == nullptr) {
133         return result.c_str();
134     }
135     // found symbols in file
136     reader->ReadFeatureSection();
137     for (auto &featureSection : reader->GetFeatureSections()) {
138         if (featureSection.get()->featureId_ == FEATURE::HIPERF_FILES_SYMBOL) {
139             const PerfFileSectionSymbolsFiles *sectionSymbolsFiles =
140                 static_cast<const PerfFileSectionSymbolsFiles *>(featureSection.get());
141             auto it = sectionSymbolsFiles->symbolFileStructs_.begin();
142             while (it != sectionSymbolsFiles->symbolFileStructs_.end()) {
143                 if (it != sectionSymbolsFiles->symbolFileStructs_.begin()) {
144                     result.append(",");
145                 }
146                 HLOGD("%s buildId:%s\n", it->filePath_.c_str(), it->buildId_.c_str());
147                 result.append("[");
148                 result.append(it->filePath_.c_str());
149                 result.append(",");
150                 result.append(it->buildId_.c_str());
151                 result.append("]");
152                 it++;
153             }
154         }
155     }
156     return result.c_str();
157 }
158 
CovertByteBufferToHexString(const unsigned char * buffer,size_t size)159 static std::string CovertByteBufferToHexString(const unsigned char *buffer, size_t size)
160 {
161     if (buffer == nullptr) {
162         HLOGE("param is null");
163         return "";
164     }
165     std::string descString;
166     size_t i = 0;
167     while (i < size) {
168         descString.append(ToHex(buffer[i]));
169         i++; // move to next char
170     }
171     return descString;
172 }
173 
ElfGetBuildId(const unsigned char * buffer,size_t size)174 static std::string ElfGetBuildId(const unsigned char *buffer, size_t size)
175 {
176     if (buffer == nullptr) {
177         HLOGE("buffer is nullptr");
178         return EMPTY_STRING;
179     }
180     const unsigned char *end = buffer + size;
181     HLOGV("size:%zu", size);
182     static constexpr const int elfNoteSectionLens = sizeof(uint32_t) * 3;
183 
184     while (end - buffer >= elfNoteSectionLens) {
185         uint32_t namesz;
186         uint32_t descsz;
187         uint32_t type;
188         CopyFromBufferAndMove(buffer, &namesz);
189         CopyFromBufferAndMove(buffer, &descsz);
190         CopyFromBufferAndMove(buffer, &type);
191 
192         // to ensure 4-byte alignment for the descriptor.
193         constexpr const int elfNoteSectionNameAlign = 4;
194 
195         namesz = RoundUp(namesz, elfNoteSectionNameAlign);
196         descsz = RoundUp(descsz, elfNoteSectionNameAlign);
197         HLOGD("namesz:%u descsz:%u type:%u", namesz, descsz, type);
198 
199         // size enough ?
200         if (buffer >= end) {
201             return EMPTY_STRING;
202         }
203         if (type == NT_GNU_BUILD_ID) {
204             char name[namesz + 1];
205             CopyFromBufferAndMove(buffer, &name[0], namesz);
206             name[namesz] = 0;
207             HLOGD("found buildid name:%s", name);
208             if (strcmp(name, ELF_NOTE_GNU) == 0) {
209                 std::string descString = CovertByteBufferToHexString(buffer, descsz);
210                 HLOGD("found buildid:%s", descString.c_str());
211                 return descString;
212             } else {
213                 // next
214                 buffer += descsz;
215             }
216         } else {
217             // next
218             buffer += namesz + descsz;
219         }
220     }
221     return EMPTY_STRING; // found nothing
222 }
223 
ReportGetBuildId(const char * elfPath)224 const char *ReportGetBuildId(const char *elfPath)
225 {
226     static std::string buildId; // statci for hold the c_str buffer
227     buildId.clear();
228     std::unique_ptr<ElfFile> elfFile = ElfFile::MakeUnique(elfPath);
229     if (elfFile == nullptr) {
230         printf("elf '%s' load failed\n", elfPath);
231     } else {
232         for (const auto &shdrPair : elfFile->shdrs_) {
233             const auto &shdr = shdrPair.second;
234             if (shdr->secType_ == SHT_NOTE) {
235                 const unsigned char *data = elfFile->GetSectionData(shdr->secIndex_);
236                 buildId = ElfGetBuildId(data, shdr->secSize_);
237                 if (!buildId.empty()) {
238                     HLOGD("%s buildId:%s\n", elfPath, buildId.c_str());
239                     return buildId.c_str();
240                 }
241             }
242         }
243         printf("elf '%s' have not found buildId\n", elfPath);
244     }
245     return buildId.c_str();
246 }
247 
ReportGetElfArch(const char * elfPath)248 const char *ReportGetElfArch(const char *elfPath)
249 {
250     const char *machineName = "unknown";
251     std::unique_ptr<ElfFile> elfFile = ElfFile::MakeUnique(elfPath);
252     static std::string result; // statci for hold the c_str buffer
253     result.clear();
254     if (elfFile == nullptr or elfFile->ehdr_ == nullptr) {
255         printf("elf '%s' load failed\n", elfPath);
256     } else {
257         switch (elfFile->ehdr_->machine_) {
258             case EM_ARM:
259                 machineName = "arm";
260                 break;
261             case EM_AARCH64:
262                 machineName = "arm64";
263                 break;
264             case EM_386:
265                 machineName = "x86";
266                 break;
267             case EM_X86_64:
268                 machineName = "x86_64";
269                 break;
270             default:
271                 machineName = "unknown";
272                 break;
273         }
274         HLOGD("elf '%s' mache value is '%x'(%s) \n", elfPath, elfFile->ehdr_->machine_,
275               machineName);
276     }
277     return machineName;
278 }
279 
Dump(const char * fileName)280 int Dump(const char *fileName)
281 {
282     std::unique_ptr<SubCommandDump> dump = std::make_unique<SubCommandDump>();
283     HLOGD("dump the file %s\n", fileName);
284     if (fileName != nullptr) {
285         std::vector<std::string> args;
286         args.emplace_back(fileName);
287         if (dump->ParseOption(args)) {
288             return dump->OnSubCommand(args) ? 0 : -1;
289         }
290     }
291     return -1;
292 }
293 
294 } // extern "C"
295