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