• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "executor/file_stream_dumper.h"
16 #include <dirent.h>
17 #include <unistd.h>
18 #include "dump_utils.h"
19 
20 namespace OHOS {
21 namespace HiviewDFX {
FileStreamDumper()22 FileStreamDumper::FileStreamDumper()
23     :fp_(nullptr),
24     fd_(-1),
25     next_file_index_(0),
26     more_data_(false),
27     need_loop_(false)
28 {
29 }
30 
~FileStreamDumper()31 FileStreamDumper::~FileStreamDumper()
32 {
33     CloseFd();
34 }
35 
PreExecute(const std::shared_ptr<DumperParameter> & parameter,StringMatrix dumpDatas)36 DumpStatus FileStreamDumper::PreExecute(const std::shared_ptr<DumperParameter>& parameter,
37     StringMatrix dumpDatas)
38 {
39     if (dumpDatas != nullptr) {
40         result_ = dumpDatas;
41     }
42 
43     // open first file!
44     if (next_file_index_ <= 0) {
45         std::string target = ptrDumpCfg_->target_;
46         if (target == "/sys/kernel/debug/binder/state") {
47             needHideAddr_ = true;
48         }
49         bool arg_pid = false;
50         bool arg_cpuid = false;
51         int pid = 0;
52         int cpuid = 0;
53         if (ptrDumpCfg_->args_.get()) {
54             arg_pid = ptrDumpCfg_->args_->HasPid();
55             arg_cpuid = ptrDumpCfg_->args_->HasCpuId();
56             pid = ptrDumpCfg_->args_->GetPid();
57             cpuid = ptrDumpCfg_->args_->GetCpuId();
58         }
59         BuildFileNames(target, arg_pid, pid, arg_cpuid, cpuid);
60         need_loop_ = (ptrDumpCfg_->loop_ == DumperConstant::LOOP);
61 
62         int ret = OpenNextFile();
63         if (ret <= 0) {
64             return DumpStatus::DUMP_FAIL;
65         }
66     }
67 
68     return DumpStatus::DUMP_OK;
69 }
70 
OpenNextFile()71 int FileStreamDumper::OpenNextFile()
72 {
73     // Close current file.
74     CloseFd();
75     if (next_file_index_ >= filenames_.size()) {
76         // no more files
77         return 0;
78     }
79     // Next file
80     std::string filename = filenames_[next_file_index_];
81     // Open fd and fp
82     if ((fd_ = DumpUtils::FdToRead(filename)) == -1) {
83         return -1;
84     }
85     if ((fp_ = fdopen(fd_, "r")) == nullptr) {
86         close(fd_);
87         fd_ = -1;
88         return -1;
89     }
90     next_file_index_ ++;
91     // add file name into buffer
92     std::vector<std::string> line_vector_blank;
93     line_vector_blank.push_back("");
94     std::vector<std::string> line_vector_filename;
95     line_vector_filename.push_back(filename);
96     result_->push_back(line_vector_blank);
97     result_->push_back(line_vector_filename);
98     result_->push_back(line_vector_blank);
99     return next_file_index_;
100 }
101 
ReplaceAddresses(const std::string & input)102 std::string FileStreamDumper::ReplaceAddresses(const std::string& input)
103 {
104     std::string result = input;
105     size_t start = result.find(": u");
106     if (start == std::string::npos) {
107         return result;
108     }
109     std::string replacement = ": u0000000000000000 c0000000000000000";
110     if (start < result.length()) {
111         result.replace(start, replacement.length(), replacement);
112     }
113     return result;
114 }
115 
116 // read one line
ReadLineInFile()117 DumpStatus FileStreamDumper::ReadLineInFile()
118 {
119     DumpStatus ret = DumpStatus::DUMP_MORE_DATA;
120     if (fp_ == nullptr) {
121         return DumpStatus::DUMP_FAIL;
122     }
123     char* line_buffer = nullptr;
124     size_t len = 0;
125     ssize_t read = 0;
126     read = getline(&line_buffer, &len, fp_);
127     if (read != -1) {
128         if (line_buffer[read-1] == '\n') {
129             line_buffer[read-1] = '\0'; // replease \n
130         }
131         std::string line = line_buffer;
132         if (needHideAddr_ && DumpUtils::IsUserMode()) {
133             line = ReplaceAddresses(line);
134         }
135         std::vector<std::string> line_vector;
136         line_vector.push_back(line);
137         result_->push_back(line_vector);
138     } else {
139         if (feof(fp_) == 0) { // ferror()
140             ret = DumpStatus::DUMP_FAIL;
141         }
142     }
143     // end of file
144     if (feof(fp_) != 0) {
145         int more_file = OpenNextFile();
146         if (more_file > 0) {
147             ret = DumpStatus::DUMP_MORE_DATA;
148         } else if (more_file == 0) {
149             ret = DumpStatus::DUMP_OK;
150         } else { // Error!
151             ret = DumpStatus::DUMP_FAIL;
152         }
153     }
154     if (line_buffer != nullptr) {
155         free(line_buffer);
156         line_buffer = nullptr;
157     }
158     more_data_ = (ret == DumpStatus::DUMP_MORE_DATA);
159     return ret;
160 }
161 
Execute()162 DumpStatus FileStreamDumper::Execute()
163 {
164     DumpStatus ret = DumpStatus::DUMP_OK;
165     if (need_loop_) {
166         // file dump one line
167         return ReadLineInFile();
168     } else {
169         // file dump all line
170         do {
171             if (IsCanceled()) {
172                 break;
173             }
174             ret = ReadLineInFile();
175         } while (ret == DumpStatus::DUMP_MORE_DATA);
176     }
177     return ret;
178 }
179 
AfterExecute()180 DumpStatus FileStreamDumper::AfterExecute()
181 {
182     if (!more_data_) {
183         CloseFd();
184         if (ptrDumpCfg_->target_ == "/sys/kernel/debug/binder/state") {
185             //The file /sys/kernel/debug/binder/state has been read, set needHideAddr_ false.
186             needHideAddr_ = false;
187         }
188         return DumpStatus::DUMP_OK;
189     }
190     return DumpStatus::DUMP_MORE_DATA;
191 }
192 
BuildFileNames(const std::string & target,bool arg_pid,int pid,bool arg_cpuid,int cpuid)193 void FileStreamDumper::BuildFileNames(const std::string& target, bool arg_pid, int pid,
194     bool arg_cpuid, int cpuid)
195 {
196     DIR* dir = opendir(target.c_str());
197     if (dir != nullptr) {
198         std::string dir_name = target;
199         // add backslash at tail of target
200         std::string backslash = "/";
201         if (dir_name.compare(dir_name.size() - backslash.size(), backslash.size(), backslash) != 0) {
202             dir_name.append(backslash);
203         }
204         dirent* ptr = nullptr;
205         while ((ptr = readdir(dir)) != nullptr) {
206             std::string d_name = ptr->d_name;
207             if ((d_name == ".") || (d_name == "..")) {
208                 continue;
209             }
210             std::string filename = dir_name + d_name;
211 
212             if (arg_pid) {
213                 ReplacePidInFilename(filename, pid);
214             }
215             if (arg_cpuid) {
216                 ReplaceCpuidInFilename(filename, cpuid);
217             }
218             filenames_.push_back(filename);
219         }
220         closedir(dir);
221     } else {
222         std::string filename = target;
223         if (arg_pid) {
224             ReplacePidInFilename(filename, pid);
225         }
226         if (arg_cpuid) {
227             ReplaceCpuidInFilename(filename, cpuid);
228         }
229         filenames_.push_back(filename);
230     }
231 }
232 
ReplacePidInFilename(std::string & filename,int pid)233 void FileStreamDumper::ReplacePidInFilename(std::string& filename, int pid)
234 {
235     // replease %pid in filename
236     size_t pos = filename.find("%pid");
237     if (pos != std::string::npos) {
238         filename = filename.replace(pos, strlen("%pid"), std::to_string(pid));
239     }
240 }
241 
ReplaceCpuidInFilename(std::string & filename,int cpuid)242 void FileStreamDumper::ReplaceCpuidInFilename(std::string& filename, int cpuid)
243 {
244     // replease %cpuid in filename
245     size_t pos = filename.find("%cpuid");
246     if (pos != std::string::npos) {
247         filename = filename.replace(pos, strlen("%cpuid"), std::to_string(cpuid));
248     }
249 }
250 
CloseFd()251 void FileStreamDumper::CloseFd()
252 {
253     if (fp_ != nullptr) {
254         fclose(fp_);
255         fp_ = nullptr;
256         fd_ = -1;
257     }
258 };
259 } // namespace HiviewDFX
260 } // namespace OHOS
261