• 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     std::string descString;
162     size_t i = 0;
163     while (i < size) {
164         descString.append(ToHex(buffer[i]));
165         i++; // move to next char
166     }
167     return descString;
168 }
169 
ElfGetBuildId(const unsigned char * buffer,size_t size)170 static std::string ElfGetBuildId(const unsigned char *buffer, size_t size)
171 {
172     if (buffer == nullptr) {
173         HLOGE("buffer is nullptr");
174         return EMPTY_STRING;
175     }
176     const unsigned char *end = buffer + size;
177     HLOGV("size:%zu", size);
178     static constexpr const int elfNoteSectionLens = sizeof(uint32_t) * 3;
179 
180     while (end - buffer >= elfNoteSectionLens) {
181         uint32_t namesz;
182         uint32_t descsz;
183         uint32_t type;
184         CopyFromBufferAndMove(buffer, &namesz);
185         CopyFromBufferAndMove(buffer, &descsz);
186         CopyFromBufferAndMove(buffer, &type);
187 
188         // to ensure 4-byte alignment for the descriptor.
189         constexpr const int elfNoteSectionNameAlign = 4;
190 
191         namesz = RoundUp(namesz, elfNoteSectionNameAlign);
192         descsz = RoundUp(descsz, elfNoteSectionNameAlign);
193         HLOGD("namesz:%u descsz:%u type:%u", namesz, descsz, type);
194 
195         // size enough ?
196         if (buffer >= end) {
197             return EMPTY_STRING;
198         }
199         if (type == NT_GNU_BUILD_ID) {
200             char name[namesz + 1];
201             CopyFromBufferAndMove(buffer, &name[0], namesz);
202             name[namesz] = 0;
203             HLOGD("found buildid name:%s", name);
204             if (strcmp(name, ELF_NOTE_GNU) == 0) {
205                 std::string descString = CovertByteBufferToHexString(buffer, descsz);
206                 HLOGD("found buildid:%s", descString.c_str());
207                 return descString;
208             } else {
209                 // next
210                 buffer += descsz;
211             }
212         } else {
213             // next
214             buffer += namesz + descsz;
215         }
216     }
217     return EMPTY_STRING; // found nothing
218 }
219 
ReportGetBuildId(const char * elfPath)220 const char *ReportGetBuildId(const char *elfPath)
221 {
222     static std::string buildId; // statci for hold the c_str buffer
223     buildId.clear();
224     std::unique_ptr<ElfFile> elfFile = ElfFile::MakeUnique(elfPath);
225     if (elfFile == nullptr) {
226         printf("elf '%s' load failed\n", elfPath);
227     } else {
228         for (const auto &shdrPair : elfFile->shdrs_) {
229             const auto &shdr = shdrPair.second;
230             if (shdr->secType_ == SHT_NOTE) {
231                 const unsigned char *data = elfFile->GetSectionData(shdr->secIndex_);
232                 buildId = ElfGetBuildId(data, shdr->secSize_);
233                 if (!buildId.empty()) {
234                     HLOGD("%s buildId:%s\n", elfPath, buildId.c_str());
235                     return buildId.c_str();
236                 }
237             }
238         }
239         printf("elf '%s' have not found buildId\n", elfPath);
240     }
241     return buildId.c_str();
242 }
243 
ReportGetElfArch(const char * elfPath)244 const char *ReportGetElfArch(const char *elfPath)
245 {
246     const char *machineName = "unknown";
247     static std::string buildId; // statci for hold the c_str buffer
248     std::unique_ptr<ElfFile> elfFile = ElfFile::MakeUnique(elfPath);
249     static std::string result; // statci for hold the c_str buffer
250     result.clear();
251     if (elfFile == nullptr or elfFile->ehdr_ == nullptr) {
252         printf("elf '%s' load failed\n", elfPath);
253     } else {
254         switch (elfFile->ehdr_->machine_) {
255             case EM_ARM:
256                 machineName = "arm";
257                 break;
258             case EM_AARCH64:
259                 machineName = "arm64";
260                 break;
261             case EM_386:
262                 machineName = "x86";
263                 break;
264             case EM_X86_64:
265                 machineName = "x86_64";
266                 break;
267             default:
268                 machineName = "unknown";
269                 break;
270         }
271         HLOGD("elf '%s' mache value is '%x'(%s) \n", elfPath, elfFile->ehdr_->machine_,
272               machineName);
273     }
274     return machineName;
275 }
276 
Dump(const char * fileName)277 int Dump(const char *fileName)
278 {
279     std::unique_ptr<SubCommandDump> dump = std::make_unique<SubCommandDump>();
280     HLOGD("dump the file %s\n", fileName);
281     if (fileName != nullptr) {
282         std::vector<std::string> args;
283         args.emplace_back(fileName);
284         if (dump->ParseOption(args)) {
285             return dump->OnSubCommand(args) ? 0 : -1;
286         }
287     }
288     return -1;
289 }
290 
291 } // extern "C"