• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "decorative_dump_info.h"
16 #include <dirent.h>
17 #include "dfx_util.h"
18 #include "dfx_dump_request.h"
19 #include "dfx_process.h"
20 #include "unwinder.h"
21 #include "dfx_trace.h"
22 #include "dfx_buffer_writer.h"
23 #include "dfx_log.h"
24 namespace OHOS {
25 namespace HiviewDFX {
26 namespace {
27 #define FD_TABLE_SIZE 128
28 const int ARG_MAX_NUM = 131072;
29 
30 struct FdEntry {
31     _Atomic(uint64_t) close_tag;
32     _Atomic(char) signal_flag;
33 };
34 
35 struct FdTableOverflow {
36     size_t len;
37     struct FdEntry entries[];
38 };
39 
40 struct FdTable {
41     _Atomic(enum fdsan_error_level) error_level;
42     struct FdEntry entries[FD_TABLE_SIZE];
43     _Atomic(struct FdTableOverflow*) overflow;
44 };
45 }
46 REGISTER_DUMP_INFO_CLASS(OpenFiles);
47 
Print(DfxProcess & process,const ProcessDumpRequest & request,Unwinder & unwinder)48 void OpenFiles::Print(DfxProcess& process, const ProcessDumpRequest& request, Unwinder& unwinder)
49 {
50     DecorativeDumpInfo::Print(process, request, unwinder);
51     DFX_TRACE_SCOPED("GetOpenFiles");
52     OpenFilesList openFies;
53     CollectOpenFiles(openFies, process.GetProcessInfo().pid);
54     FillFdsaninfo(openFies, process.GetProcessInfo().nsPid, request.fdTableAddr);
55     DfxBufferWriter::GetInstance().WriteMsg(DumpOpenFiles(openFies));
56     DFXLOGI("get open files info finish");
57 }
58 
ReadLink(std::string & src,std::string & dst)59 bool OpenFiles::ReadLink(std::string &src, std::string &dst)
60 {
61     char buf[PATH_MAX];
62     ssize_t count = readlink(src.c_str(), buf, sizeof(buf) - 1);
63     if (count < 0) {
64         return false;
65     }
66     buf[count] = '\0';
67     dst = buf;
68     return true;
69 }
70 
CollectOpenFiles(OpenFilesList & list,pid_t pid)71 void OpenFiles::CollectOpenFiles(OpenFilesList &list, pid_t pid)
72 {
73     std::string fdDirName = "/proc/" + std::to_string(pid) + "/fd";
74     std::unique_ptr<DIR, int (*)(DIR *)> dir(opendir(fdDirName.c_str()), closedir);
75     if (dir == nullptr) {
76         DFXLOGE("failed to open directory %{public}s: %{public}s", fdDirName.c_str(), strerror(errno));
77         return;
78     }
79 
80     struct dirent *de;
81     while ((de = readdir(dir.get())) != nullptr) {
82         if (*de->d_name == '.') {
83             continue;
84         }
85 
86         int fd = atoi(de->d_name);
87         std::string path = fdDirName + "/" + std::string(de->d_name);
88         std::string target;
89         if (ReadLink(path, target)) {
90             list[fd].path = target;
91         } else {
92             list[fd].path = "???";
93             DFXLOGE("failed to readlink %{public}s: %{public}s", path.c_str(), strerror(errno));
94         }
95     }
96 }
97 
FillFdsaninfo(OpenFilesList & list,pid_t nsPid,uint64_t fdTableAddr)98 void OpenFiles::FillFdsaninfo(OpenFilesList &list, pid_t nsPid, uint64_t fdTableAddr)
99 {
100     constexpr size_t fds = sizeof(FdTable::entries) / sizeof(*FdTable::entries);
101     size_t entryOffset = offsetof(FdTable, entries);
102     uint64_t addr = fdTableAddr + entryOffset;
103     FdEntry entrys[fds];
104     if (ReadProcMemByPid(nsPid, addr, entrys, sizeof(FdEntry) * fds) != sizeof(FdEntry) * fds) {
105         DFXLOGE("[%{public}d]: read nsPid mem error %{public}s", __LINE__, strerror(errno));
106         return;
107     }
108     for (size_t i = 0; i < fds; i++) {
109         if (entrys[i].close_tag) {
110             list[i].fdsanOwner = entrys[i].close_tag;
111         }
112     }
113 
114     size_t overflowOffset = offsetof(FdTable, overflow);
115     uintptr_t overflow = 0;
116     uint64_t tmp = fdTableAddr + overflowOffset;
117     if (ReadProcMemByPid(nsPid, tmp, &overflow, sizeof(overflow)) != sizeof(overflow)) {
118         return;
119     }
120     if (!overflow) {
121         return;
122     }
123 
124     size_t overflowLength;
125     if (ReadProcMemByPid(nsPid, overflow, &overflowLength, sizeof(overflowLength)) != sizeof(overflowLength)) {
126         return;
127     }
128     if (overflowLength > ARG_MAX_NUM) {
129         return;
130     }
131 
132     std::vector<FdEntry> overflowFdEntrys(overflowLength);
133     uint64_t address = overflow + offsetof(FdTableOverflow, entries);
134     if (ReadProcMemByPid(nsPid, address, overflowFdEntrys.data(), sizeof(FdEntry) * overflowLength) !=
135         sizeof(FdEntry) * overflowLength) {
136         DFXLOGE("[%{public}d]: read nsPid mem error %{public}s", __LINE__, strerror(errno));
137         return;
138     }
139     size_t fdIndex = fds;
140     for (size_t i = 0; i < overflowLength; i++) {
141         if (overflowFdEntrys[i].close_tag) {
142             list[fdIndex].fdsanOwner = overflowFdEntrys[i].close_tag;
143         }
144         fdIndex++;
145     }
146 }
147 
DumpOpenFiles(OpenFilesList files)148 std::string OpenFiles::DumpOpenFiles(OpenFilesList files)
149 {
150     std::string openFilesStr = "OpenFiles:\n";
151     for (const auto &filePath: files) {
152         const std::string path = filePath.second.path;
153         uint64_t tag = filePath.second.fdsanOwner;
154         const char* type = fdsan_get_tag_type(tag);
155         uint64_t val = fdsan_get_tag_value(tag);
156         if (!path.empty()) {
157             openFilesStr += std::to_string(filePath.first) + "->" + path + " " + type + " " +
158                 std::to_string(val) + "\n";
159         } else {
160             openFilesStr += "OpenFilesList contain an entry (fd " +
161                 std::to_string(filePath.first) + ") with no path or owner\n";
162         }
163     }
164     return openFilesStr;
165 }
166 }
167 }