• 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 #define HILOG_TAG "Runtime"
16 
17 #include "virtual_runtime.h"
18 
19 #include <cinttypes>
20 #include <iostream>
21 #include <sstream>
22 #include <unistd.h>
23 #if !is_mingw
24 #include <sys/mman.h>
25 #endif
26 
27 #include "register.h"
28 #include "symbols_file.h"
29 #include "utilities.h"
30 
31 using namespace std::chrono;
32 namespace OHOS {
33 namespace Developtools {
34 namespace NativeDaemon {
35 namespace {
36 std::atomic<uint64_t> callStackErrCnt = 0;
37 constexpr uint32_t CALL_STACK_ERROR_TIMES = 10;
38 constexpr uint32_t SYMBOL_FILES_SIZE = 512;
39 }
40 // we unable to access 'swapper' from /proc/0/
ClearMaps()41 void VirtualRuntime::ClearMaps()
42 {
43     processMemMaps_.clear();
44 }
45 
VirtualRuntime(const NativeHookConfig & hookConfig)46 VirtualRuntime::VirtualRuntime(const NativeHookConfig& hookConfig): hookConfig_(hookConfig)
47 {
48     symbolsFiles_.reserve(SYMBOL_FILES_SIZE);
49     if (!hookConfig_.offline_symbolization()) {
50         userSymbolCache_.reserve(USER_SYMBOL_CACHE_LIMIT);
51     }
52 }
53 
~VirtualRuntime()54 VirtualRuntime::~VirtualRuntime()
55 {
56     HILOG_INFO(LOG_CORE, "%s:%d UserSymbolCache size = %zu", __func__, __LINE__, userSymbolCache_.size());
57     HILOG_INFO(LOG_CORE, "Total number of call stack errors: %" PRIu64 "", callStackErrCnt.load());
58     ClearMaps();
59 }
60 
ReadThreadName(pid_t tid)61 std::string VirtualRuntime::ReadThreadName(pid_t tid)
62 {
63     std::string comm = ReadFileToString(StringPrintf("/proc/%d/comm", tid)).c_str();
64     comm.erase(std::remove(comm.begin(), comm.end(), '\r'), comm.end());
65     comm.erase(std::remove(comm.begin(), comm.end(), '\n'), comm.end());
66     return comm;
67 }
68 
UpdateThread(pid_t pid,pid_t tid,const std::string name)69 VirtualThread &VirtualRuntime::UpdateThread(pid_t pid, pid_t tid, const std::string name)
70 {
71 #ifdef HIPERF_DEBUG_TIME
72     const auto startTime = steady_clock::now();
73 #endif
74     VirtualThread &thread = GetThread(pid, tid);
75     if (!name.empty()) {
76         thread.name_ = name;
77     }
78 #ifdef HIPERF_DEBUG_TIME
79     updateThreadTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
80 #endif
81     return thread;
82 }
83 
CreateThread(pid_t pid,pid_t tid)84 VirtualThread &VirtualRuntime::CreateThread(pid_t pid, pid_t tid)
85 {
86     // make a new one
87     userSpaceThreadMap_.emplace(std::piecewise_construct, std::forward_as_tuple(tid),
88                                 std::forward_as_tuple(pid, tid, symbolsFiles_, this));
89     VirtualThread& thr = userSpaceThreadMap_.at(tid);
90     return thr;
91 }
92 
GetThread(pid_t pid,pid_t tid)93 VirtualThread &VirtualRuntime::GetThread(pid_t pid, pid_t tid)
94 {
95     HLOGV("find thread %u:%u", pid, tid);
96     auto it = userSpaceThreadMap_.find(tid);
97     if (it == userSpaceThreadMap_.end()) {
98         // we also need thread
99         VirtualThread& thr = CreateThread(pid, tid);
100         return thr;
101     } else {
102         VirtualThread& thr = it->second;
103         return thr;
104     }
105 }
106 
MakeCallFrame(Symbol & symbol,CallFrame & callFrame)107 void VirtualRuntime::MakeCallFrame(Symbol &symbol, CallFrame &callFrame)
108 {
109     callFrame.vaddrInFile_ = symbol.funcVaddr_;
110     callFrame.symbolName_ = symbol.symbolName_;
111     callFrame.symbolIndex_ = symbol.index_;
112     callFrame.filePath_ = symbol.module_.empty() ? symbol.comm_ : symbol.module_;
113     callFrame.symbolOffset_ = symbol.offset_;
114     callFrame.callFrameId_ = symbol.symbolId_;
115     callFrame.symbolNameId_ = symbol.symbolNameId_;
116     callFrame.filePathId_ = symbol.filePathId_;
117     if (symbol.funcVaddr_ != 0) {
118         callFrame.offset_ = symbol.funcVaddr_;
119     } else {
120         callFrame.offset_ = callFrame.ip_;
121     }
122 }
123 
GetSymbolName(pid_t pid,pid_t tid,std::vector<CallFrame> & callFrames,int offset,bool first)124 bool VirtualRuntime::GetSymbolName(pid_t pid, pid_t tid, std::vector<CallFrame>& callFrames, int offset, bool first)
125 {
126 #ifdef HIPERF_DEBUG_TIME
127     const auto startTime = steady_clock::now();
128 #endif
129     // Symbolic the Call Stack
130     HLOGV("total %zu frames", callFrames.size());
131 
132     perf_callchain_context perfCallchainContext = PERF_CONTEXT_MAX;
133     for (auto callFrameIt = callFrames.begin() + offset; callFrameIt != callFrames.end(); ++callFrameIt) {
134         auto &callFrame = callFrameIt.operator*();
135         if (callFrame.ip_ >= PERF_CONTEXT_MAX) {
136             // dont care, this is not issue.
137             HLOGV("%s", UpdatePerfContext(callFrame.ip_, perfCallchainContext).c_str());
138             continue;
139         }
140         auto symbol = GetSymbol(callFrame, pid, tid,
141             perfCallchainContext);
142         if (symbol.isValid()) {
143             MakeCallFrame(symbol, callFrame);
144         } else {
145 #ifdef TRY_UNWIND_TWICE
146             if (first) {
147                 if (failedIPs_.find(callFrame.ip_) == failedIPs_.end()) {
148                     return false;
149                 } else {
150                     callFrames.erase(callFrameIt, callFrames.end());
151                     return true;
152                 }
153             } else {
154                 failedIPs_.insert(callFrame.ip_);
155                 callFrames.erase(callFrameIt, callFrames.end());
156                 return true;
157             }
158 #else
159             ++callStackErrCnt;
160             if (callStackErrCnt.load() % CALL_STACK_ERROR_TIMES == 0) {
161                 HILOG_DEBUG(LOG_CORE, "number of call stack errors: %" PRIu64 "", callStackErrCnt.load());
162             }
163             callFrames.erase(callFrameIt, callFrames.end());
164             return true;
165 #endif
166         }
167         int index = callFrameIt - callFrames.begin();
168         HLOGV(" (%u)unwind symbol: %*s%s", index, index, "", callFrame.ToSymbolString().c_str());
169     }
170 #ifdef HIPERF_DEBUG_TIME
171     auto usedTime = duration_cast<microseconds>(steady_clock::now() - startTime);
172     if (usedTime.count() != 0) {
173         HLOGV("cost %0.3f ms to symbolic ", usedTime.count() / MS_DUARTION);
174     }
175     symbolicRecordTimes_ += usedTime;
176 #endif
177     return true;
178 }
179 
UpdateMaps(pid_t pid,pid_t tid)180 void VirtualRuntime::UpdateMaps(pid_t pid, pid_t tid)
181 {
182     auto &thread = UpdateThread(pid, tid);
183     if (thread.ParseMap(processMemMaps_, true)) {
184         HILOG_DEBUG(LOG_CORE, "voluntarily update maps succeed");
185     } else {
186         HILOG_DEBUG(LOG_CORE, "voluntarily update maps ignore");
187     }
188 }
189 
UnwindStack(std::vector<u64> & regs,const u8 * stack_addr,int stack_size,pid_t pid,pid_t tid,std::vector<CallFrame> & callFrames,size_t maxStackLevel)190 bool VirtualRuntime::UnwindStack(std::vector<u64>& regs,
191                                  const u8* stack_addr,
192                                  int stack_size,
193                                  pid_t pid,
194                                  pid_t tid,
195                                  std::vector<CallFrame>& callFrames,
196                                  size_t maxStackLevel)
197 {
198 #ifdef HIPERF_DEBUG_TIME
199     const auto startTime = steady_clock::now();
200 #endif
201     // if we have userstack ?
202     int offset = 0;
203     auto &thread = UpdateThread(pid, tid);
204     if (stack_size > 0) {
205         callstack_.UnwindCallStack(thread, &regs[0], regs.size(), stack_addr, stack_size, callFrames, maxStackLevel);
206         if (callFrames.size() <= FILTER_STACK_DEPTH) {
207             callFrames.clear();
208             return false;
209         }
210         // Do not symbolize the first two frame, cause the two frame implement by tool itself
211         offset = FILTER_STACK_DEPTH;
212 #ifdef HIPERF_DEBUG_TIME
213         unwindCallStackTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
214 #endif
215     }
216 #ifdef HIPERF_DEBUG_TIME
217     unwindFromRecordTimes_ += duration_cast<microseconds>(steady_clock::now() - startTime);
218 #endif
219     if (hookConfig_.offline_symbolization()) {
220         return true;
221     }
222     if (!GetSymbolName(pid, tid, callFrames, offset, true)) {
223 #ifdef TRY_UNWIND_TWICE
224         HLOGD("clear and unwind one more time");
225         if (!thread.ParseMap(processMemMaps_, true)) {
226             GetSymbolName(pid, tid, callFrames, offset, false);
227             return false;
228         }
229         if (stack_size > 0) {
230             callFrames.clear();
231             callstack_.UnwindCallStack(thread, &regs[0], regs.size(), stack_addr,
232                 stack_size, callFrames, maxStackLevel);
233         }
234         if (callFrames.size() <= FILTER_STACK_DEPTH) {
235             callFrames.clear();
236             return false;
237         }
238         if (!GetSymbolName(pid, tid, callFrames, offset, false)) {
239             return false;
240         }
241 #endif
242     }
243     return true;
244 }
245 
IsSymbolExist(const std::string & fileName)246 bool VirtualRuntime::IsSymbolExist(const std::string& fileName)
247 {
248     if (symbolsFiles_.find(fileName) != symbolsFiles_.end()) {
249         HLOGV("already have '%s'", fileName.c_str());
250         return true;
251     }
252     return false;
253 }
254 
DelSymbolFile(const std::string & fileName)255 void VirtualRuntime::DelSymbolFile(const std::string& fileName)
256 {
257     symbolsFiles_.erase(fileName);
258 }
259 
UpdateSymbols(std::string fileName)260 void VirtualRuntime::UpdateSymbols(std::string fileName)
261 {
262     HLOGD("try to find symbols for file: %s", fileName.c_str());
263 #ifdef HIPERF_DEBUG_TIME
264     const auto startTime = steady_clock::now();
265 #endif
266     if (symbolsFiles_.find(fileName) != symbolsFiles_.end()) {
267         HLOGV("already have '%s'", fileName.c_str());
268         return;
269     }
270 
271     // found it by name
272     auto symbolsFile = SymbolsFile::CreateSymbolsFile(fileName);
273 
274     // set sybol path If it exists
275     if (symbolsPaths_.size() > 0) {
276         symbolsFile->setSymbolsFilePath(symbolsPaths_); // also load from search path
277     }
278     if (loadSymboleWhenNeeded_) {
279         // load it when we need it
280         symbolsFiles_[symbolsFile->filePath_] = std::move(symbolsFile);
281     } else if (symbolsFile->LoadSymbols()) {
282         symbolsFiles_[symbolsFile->filePath_] = std::move(symbolsFile);
283     } else {
284         HLOGW("symbols file for '%s' not found.", fileName.c_str());
285     }
286 #ifdef HIPERF_DEBUG_TIME
287     auto usedTime = duration_cast<microseconds>(steady_clock::now() - startTime);
288     if (usedTime.count() != 0) {
289         HLOGV("cost %0.3f ms to load '%s'", usedTime.count() / MS_DUARTION, fileName.c_str());
290     }
291     updateSymbolsTimes_ += usedTime;
292 #endif
293 }
294 
GetKernelSymbol(uint64_t ip,const std::vector<MemMapItem> & memMaps,const VirtualThread & thread)295 const Symbol VirtualRuntime::GetKernelSymbol(uint64_t ip, const std::vector<MemMapItem> &memMaps,
296                                              const VirtualThread &thread)
297 {
298     Symbol vaddrSymbol(ip, thread.name_);
299     for (auto &map : memMaps) {
300         if (ip > map.begin_ && ip < map.end_) {
301             HLOGM("found addr 0x%" PRIx64 " in kernel map 0x%" PRIx64 " - 0x%" PRIx64 " from %s",
302                   ip, map.begin_, map.end_, map.name_.c_str());
303             vaddrSymbol.module_ = map.name_;
304             // found symbols by file name
305             auto search = symbolsFiles_.find(map.name_);
306             if (search != symbolsFiles_.end()) {
307                 auto& symbolsFile = search->second;
308                 vaddrSymbol.fileVaddr_ =
309                         symbolsFile->GetVaddrInSymbols(ip, map.begin_, map.pageoffset_);
310                 HLOGV("found symbol vaddr 0x%" PRIx64 " for runtime vaddr 0x%" PRIx64
311                         " at '%s'",
312                         vaddrSymbol.fileVaddr_, ip, map.name_.c_str());
313                 if (!symbolsFile->SymbolsLoaded()) {
314                     symbolsFile->LoadSymbols();
315                 }
316                 Symbol foundSymbols = symbolsFile->GetSymbolWithVaddr(vaddrSymbol.fileVaddr_);
317                 foundSymbols.taskVaddr_ = ip;
318                 if (!foundSymbols.isValid()) {
319                     HLOGW("addr 0x%" PRIx64 " vaddr  0x%" PRIx64 " NOT found in symbol file %s",
320                             ip, vaddrSymbol.fileVaddr_, map.name_.c_str());
321                     return vaddrSymbol;
322                 } else {
323                     return foundSymbols;
324                 }
325             }
326             HLOGW("addr 0x%" PRIx64 " in map but NOT found the symbol file %s", ip,
327                   map.name_.c_str());
328         } else {
329             HLOGM("addr 0x%" PRIx64 " not in map 0x%" PRIx64 " - 0x%" PRIx64 " from %s", ip,
330                   map.begin_, map.end_, map.name_.c_str());
331         }
332     }
333     return vaddrSymbol;
334 }
335 
GetUserSymbol(uint64_t ip,const VirtualThread & thread)336 const Symbol VirtualRuntime::GetUserSymbol(uint64_t ip, const VirtualThread &thread)
337 {
338     Symbol vaddrSymbol(ip, thread.name_);
339     auto [curMemMaps, itemIndex] = FindMap(ip);
340     if (curMemMaps != nullptr) {
341         auto symbolsFilesIter = symbolsFiles_.find(curMemMaps->name_);
342         if (symbolsFilesIter != symbolsFiles_.end()) {
343             auto symbolsFile = symbolsFilesIter->second.get();
344             symbolsFile->LoadDebugInfo();
345             vaddrSymbol.fileVaddr_ =
346                 symbolsFile->GetVaddrInSymbols(ip, curMemMaps->maps_[itemIndex].begin_,
347                                                curMemMaps->maps_[itemIndex].pageoffset_);
348             vaddrSymbol.module_ = curMemMaps->maps_[itemIndex].nameHold_;
349             vaddrSymbol.symbolName_ = vaddrSymbol.Name();
350             if (!symbolsFile->SymbolsLoaded()) {
351                 symbolsFile->LoadSymbols();
352             }
353             Symbol foundSymbols = symbolsFile->GetSymbolWithVaddr(vaddrSymbol.fileVaddr_);
354             foundSymbols.taskVaddr_ = ip;
355             foundSymbols.symbolName_ = foundSymbols.Name();
356             if (!foundSymbols.isValid()) {
357                 vaddrSymbol.filePathId_ = curMemMaps->filePathId_;
358                 return vaddrSymbol;
359             } else {
360                 foundSymbols.filePathId_ = curMemMaps->filePathId_;
361                 return foundSymbols;
362             }
363         } else {
364             HLOGW("addr 0x%" PRIx64 " in map but NOT found the symbol file %s", ip,
365                   curMemMaps->name_.c_str());
366         }
367     } else {
368         HLOGW("ReportVaddrMapMiss");
369 #ifdef HIPERF_DEBUG
370         thread.ReportVaddrMapMiss(ip);
371 #endif
372     }
373     return vaddrSymbol;
374 }
375 
GetSymbolCache(uint64_t ip,Symbol & symbol,const VirtualThread & thread)376 bool VirtualRuntime::GetSymbolCache(uint64_t ip, Symbol &symbol, const VirtualThread &thread)
377 {
378     auto [curMemMaps, itemIndex] = FindMap(ip);
379     if (curMemMaps != nullptr) {
380         auto foundSymbolIter = userSymbolCache_.find(std::pair(ip, curMemMaps->filePathId_));
381         if (foundSymbolIter != userSymbolCache_.end()) {
382             symbol = foundSymbolIter->second;
383             return true;
384         }
385     }
386     return false;
387 }
388 
UpdateSymbolCache(uint64_t ip,Symbol & symbol,HashList<uint64_t,Symbol> & cache)389 void VirtualRuntime::UpdateSymbolCache(uint64_t ip, Symbol &symbol,
390     HashList<uint64_t, Symbol> &cache)
391 {
392     // review change to LRU for memmory
393     HLOG_ASSERT_MESSAGE(cache.count(ip) == 0, "already have cached ip 0x%" PRIx64 "", ip);
394     cache[ip] = symbol;
395 }
396 
GetSymbol(CallFrame & callFrame,pid_t pid,pid_t tid,const perf_callchain_context & context)397 const Symbol VirtualRuntime::GetSymbol(CallFrame& callFrame, pid_t pid, pid_t tid,
398                                        const perf_callchain_context &context)
399 {
400     HLOGM("try find tid %u ip 0x%" PRIx64 " in %zu symbolsFiles ", tid, callFrame.ip_, symbolsFiles_.size());
401     Symbol symbol;
402     if (GetSymbolCache(callFrame.ip_, symbol, GetThread(pid, tid))) {
403         return symbol;
404     }
405     if (context == PERF_CONTEXT_USER or (context == PERF_CONTEXT_MAX and !symbol.isValid())) {
406         // check userspace memmap
407         symbol = GetUserSymbol(callFrame.ip_, GetThread(pid, tid));
408         if (symbol.isValid()) {
409             HLOGM("GetUserSymbol valid tid = %d ip = 0x%" PRIx64 "", tid, callFrame.ip_);
410             symbol.symbolId_ = userSymbolCache_.size() + 1;
411             if (hookConfig_.string_compressed()) {
412                 FillSymbolNameId(callFrame, symbol);
413                 FillFileSet(callFrame, symbol);
414             }
415             callFrame.needReport_ |= CALL_FRAME_REPORT;
416             userSymbolCache_[std::pair(callFrame.ip_, symbol.filePathId_)] = symbol;
417         } else {
418             HLOGM("GetUserSymbol invalid!");
419         }
420     }
421 
422     return symbol;
423 }
424 
SetSymbolsPaths(const std::vector<std::string> & symbolsPaths)425 bool VirtualRuntime::SetSymbolsPaths(const std::vector<std::string> &symbolsPaths)
426 {
427     std::unique_ptr<SymbolsFile> symbolsFile = SymbolsFile::CreateSymbolsFile(SYMBOL_UNKNOW_FILE);
428     // we need check if the path is accessable
429     bool accessable = symbolsFile->setSymbolsFilePath(symbolsPaths);
430     if (accessable) {
431         symbolsPaths_ = symbolsPaths;
432     } else {
433         if (!symbolsPaths.empty()) {
434             printf("some symbols path unable access\n");
435         }
436     }
437     return accessable;
438 }
439 
FillMapsCache(std::string & currentFileName,MemMapItem & memMapItem)440 void VirtualRuntime::FillMapsCache(std::string& currentFileName, MemMapItem& memMapItem)
441 {
442     if (currentFileName.compare(memMapItem.name_) != 0) {
443         currentFileName = memMapItem.name_;
444         soBegin_ = memMapItem.begin_;
445         mapsCache_[memMapItem.begin_] =
446             MemMaps(memMapItem.begin_, memMapItem.end_, memMapItem.pageoffset_,
447                     memMapItem.type_, ++memMapFilePathId_, memMapItem.name_);
448     } else {
449         if (auto curMemMapsIter = mapsCache_.find(soBegin_);
450                 curMemMapsIter != mapsCache_.end()) {
451             auto& curMemMaps = curMemMapsIter->second;
452             curMemMaps.soEnd_ = memMapItem.end_;
453             curMemMaps.maps_.back().end_ = memMapItem.begin_;
454             curMemMaps.maps_.emplace_back(memMapItem.begin_, memMapItem.end_, memMapItem.type_,
455                                           memMapItem.pageoffset_, curMemMaps.name_);
456             if (memMapItem.type_ & PROT_EXEC) {
457                 offlineMapAddr_.push_back(soBegin_);
458             }
459         }
460     }
461 }
462 
FillSymbolNameId(CallFrame & callFrame,Symbol & symbol)463 inline void VirtualRuntime::FillSymbolNameId(CallFrame& callFrame, Symbol& symbol)
464 {
465     auto itFuntion = functionMap_.find(std::string(symbol.symbolName_));
466     if (itFuntion != functionMap_.end()) {
467         symbol.symbolNameId_ = itFuntion->second;
468     } else {
469         symbol.symbolNameId_ = functionMap_.size() + 1;
470         functionMap_[std::string(symbol.symbolName_)] = symbol.symbolNameId_;
471         callFrame.needReport_ |= SYMBOL_NAME_ID_REPORT;
472     }
473 }
474 
FillFileSet(CallFrame & callFrame,const Symbol & symbol)475 inline void VirtualRuntime::FillFileSet(CallFrame& callFrame, const Symbol& symbol)
476 {
477     auto itFile = fileSet_.find(symbol.filePathId_);
478     if (itFile == fileSet_.end()) {
479         callFrame.needReport_ |= FILE_PATH_ID_REPORT;
480         fileSet_.insert(symbol.filePathId_);
481     }
482 }
483 
HandleMapInfo(uint64_t begin,uint64_t length,uint32_t flags,uint64_t offset,const std::string & filePath)484 void VirtualRuntime::HandleMapInfo(uint64_t begin, uint64_t length, uint32_t flags,
485                                    uint64_t offset, const std::string& filePath)
486 {
487     if (!(flags & MAP_FIXED) || mapsCache_.empty()) {
488         if (mapsCache_.find(begin) != mapsCache_.end()) {
489             return;
490         }
491         soBegin_ = begin;
492         mapsCache_[begin] = MemMaps(begin, begin + length, offset, flags, ++memMapFilePathId_, filePath);
493         UpdateSymbols(filePath);
494     } else {
495         auto curMemMapsIter = mapsCache_.find(soBegin_);
496         if (curMemMapsIter != mapsCache_.end()) {
497             auto& curMemMaps = curMemMapsIter->second;
498             curMemMaps.soEnd_ = begin + length;
499             curMemMaps.maps_.back().end_ = begin;
500             curMemMaps.maps_.emplace_back(begin, begin + length, (uint16_t)flags, offset, curMemMaps.name_);
501             if (flags & PROT_EXEC) {
502                 offlineMapAddr_.push_back(soBegin_);
503             }
504         }
505     }
506 }
507 
RemoveMaps(uint64_t addr)508 void VirtualRuntime::RemoveMaps(uint64_t addr)
509 {
510     mapsCache_.erase(addr);
511 }
512 
FindMap(uint64_t addr)513 std::pair<MemMaps*, uint32_t> VirtualRuntime::FindMap(uint64_t addr)
514 {
515     auto iter = mapsCache_.upper_bound(addr);
516     if (iter == mapsCache_.begin()) {
517         // have map 2 3 4 5
518         // find 1 , will return 2 (index 0, begin elem)
519         // this same as not found any thins
520         return {nullptr, 0};
521     }
522 
523     auto& curMemMaps = (--iter)->second;
524     if (addr >= curMemMaps.soBegin_ && addr < curMemMaps.soEnd_) {
525         for (auto curMemMapItem = curMemMaps.maps_.begin();
526             curMemMapItem != curMemMaps.maps_.end(); ++curMemMapItem) {
527             if (addr >= curMemMapItem->begin_ && addr < curMemMapItem->end_) {
528                 return {&(curMemMaps), curMemMapItem - curMemMaps.maps_.begin()};
529             }
530         }
531     }
532     return {nullptr, 0};
533 }
534 } // namespace NativeDaemon
535 } // namespace Developtools
536 } // namespace OHOS