mirror of
https://gitee.com/openharmony/developtools_hiperf
synced 2024-11-27 01:30:28 +00:00
fix: support unwinding sandbox library in dynamic dlopen scenario
Signed-off-by: yanmengzhao1 <yanmengzhao1@huawei.com>
This commit is contained in:
parent
56cdba760e
commit
c93b3ecfa4
@ -195,6 +195,7 @@ public:
|
||||
bool GetBinary(std::vector<uint8_t> &buf) const override;
|
||||
void DumpData(int indent) const override;
|
||||
void DumpLog(const std::string &prefix) const override;
|
||||
bool discard_ = false;
|
||||
};
|
||||
|
||||
class PerfRecordLost : public PerfEventRecord {
|
||||
|
@ -134,6 +134,13 @@ public:
|
||||
debugInfoLoaded_ = true;
|
||||
return false;
|
||||
};
|
||||
|
||||
virtual const std::unordered_map<uint64_t, ElfLoadInfo> GetPtLoads()
|
||||
{
|
||||
std::unordered_map<uint64_t, ElfLoadInfo> loadInfoMap;
|
||||
return loadInfoMap;
|
||||
}
|
||||
|
||||
// get the build if from symbols
|
||||
const std::string GetBuildId() const;
|
||||
|
||||
|
@ -341,8 +341,7 @@ bool IsSupportNonDebuggableApp();
|
||||
const std::string GetUserType();
|
||||
std::string GetProcessName(int pid);
|
||||
bool IsDebugableApp(const std::string& bundleName);
|
||||
// Sanbox lib path check
|
||||
std::string AdaptSandboxPath(std::string filePath, int pid);
|
||||
bool NeedAdaptSandboxPath(char *filename, int pid, u16 &headerSize);
|
||||
} // namespace HiPerf
|
||||
} // namespace Developtools
|
||||
} // namespace OHOS
|
||||
|
@ -204,6 +204,8 @@ private:
|
||||
FRIEND_TEST(VirtualRuntimeTest, SetDisableUnwind);
|
||||
FRIEND_TEST(VirtualRuntimeTest, UnwindFromRecord);
|
||||
friend class VirtualRuntimeTest;
|
||||
|
||||
bool CheckValidSandBoxMmap(PerfRecordMmap2 &recordMmap2);
|
||||
};
|
||||
} // namespace HiPerf
|
||||
} // namespace Developtools
|
||||
|
@ -193,6 +193,16 @@ public:
|
||||
return elfFile_;
|
||||
}
|
||||
|
||||
const std::unordered_map<uint64_t, ElfLoadInfo> GetPtLoads() override
|
||||
{
|
||||
std::unordered_map<uint64_t, ElfLoadInfo> info;
|
||||
if (elfFile_ == nullptr) {
|
||||
return info;
|
||||
}
|
||||
|
||||
return elfFile_->GetPtLoads();
|
||||
}
|
||||
|
||||
protected:
|
||||
bool LoadDebugInfo(std::shared_ptr<DfxMap> map, const std::string &symbolFilePath) override
|
||||
{
|
||||
@ -212,6 +222,10 @@ protected:
|
||||
|
||||
if (elfFile_ == nullptr) {
|
||||
if (StringEndsWith(elfPath, ".hap")) {
|
||||
if (map == nullptr) {
|
||||
HLOGW("map should not be nullptr.");
|
||||
return false;
|
||||
}
|
||||
elfFile_ = DfxElf::CreateFromHap(elfPath, map->prevMap, map->offset);
|
||||
HLOGD("try create elf from hap");
|
||||
} else {
|
||||
@ -258,6 +272,7 @@ protected:
|
||||
}
|
||||
#endif
|
||||
|
||||
HLOGD("LoadDebugInfo success!");
|
||||
debugInfoLoadResult_ = true;
|
||||
return true;
|
||||
}
|
||||
@ -414,13 +429,8 @@ private:
|
||||
return false;
|
||||
}
|
||||
|
||||
auto ptloads = elfFile_->GetPtLoads();
|
||||
for (const auto &ptload : ptloads) {
|
||||
if (textExecVaddr_ != std::min(textExecVaddr_, ptload.second.tableVaddr)) {
|
||||
textExecVaddr_ = std::min(textExecVaddr_, ptload.second.tableVaddr);
|
||||
textExecVaddrFileOffset_ = ptload.second.offset;
|
||||
}
|
||||
}
|
||||
textExecVaddr_ = elfFile_->GetStartVaddr();
|
||||
textExecVaddrFileOffset_ = elfFile_->GetStartOffset();
|
||||
HLOGD("textExecVaddr_ 0x%016" PRIx64 " file offset 0x%016" PRIx64 "", textExecVaddr_,
|
||||
textExecVaddrFileOffset_);
|
||||
|
||||
|
@ -821,12 +821,19 @@ bool IsDebugableApp(const std::string& bundleName)
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string AdaptSandboxPath(std::string filePath, int pid)
|
||||
bool NeedAdaptSandboxPath(char *filename, int pid, u16 &headerSize)
|
||||
{
|
||||
if (filePath.find("/data/storage") == 0 && access(filePath.c_str(), F_OK) != 0) {
|
||||
filePath = "/proc/" + std::to_string(pid) + "/root" + filePath;
|
||||
std::string oldFilename = filename;
|
||||
if (oldFilename.find("/data/storage") == 0 && access(oldFilename.c_str(), F_OK) != 0) {
|
||||
std::string newFilename = "/proc/" + std::to_string(pid) + "/root" + oldFilename;
|
||||
(void)memset_s(filename, KILO, '\0', KILO);
|
||||
if (strncpy_s(filename, KILO, newFilename.c_str(), newFilename.size()) != 0) {
|
||||
HLOGD("strncpy_s recordMmap2 failed!");
|
||||
}
|
||||
headerSize += newFilename.size() - oldFilename.size();
|
||||
return true;
|
||||
}
|
||||
return filePath;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace HiPerf
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include "dfx_maps.h"
|
||||
#include "dfx_map.h"
|
||||
#include "register.h"
|
||||
#include "symbols_file.h"
|
||||
#include "utilities.h"
|
||||
@ -117,8 +117,7 @@ VirtualThread &VirtualRuntime::CreateThread(pid_t pid, pid_t tid)
|
||||
// so in hap is load before start perf record
|
||||
// dynamic load library should be treat in the same way
|
||||
bool updateNormalSymbol = true;
|
||||
if (map->name.find(".hap") != std::string::npos &&
|
||||
map->prots & PROT_EXEC) {
|
||||
if (map->name.find(".hap") != std::string::npos && (map->prots & PROT_EXEC)) {
|
||||
map->prevMap = prevMap;
|
||||
updateNormalSymbol = !UpdateHapSymbols(map);
|
||||
HLOGD("UpdateHapSymbols");
|
||||
@ -482,33 +481,116 @@ void VirtualRuntime::UpdateFromRecord(PerfRecordMmap &recordMmap)
|
||||
UpdatekernelMap(recordMmap.data_.addr, recordMmap.data_.addr + recordMmap.data_.len,
|
||||
recordMmap.data_.pgoff, recordMmap.data_.filename);
|
||||
} else {
|
||||
std::string libPath = AdaptSandboxPath(recordMmap.data_.filename, recordMmap.data_.pid);
|
||||
recordMmap.header.size += libPath.size() - strlen(recordMmap.data_.filename);
|
||||
(void)memset_s(recordMmap.data_.filename, KILO, '\0', KILO);
|
||||
if (strncpy_s(recordMmap.data_.filename, KILO, libPath.c_str(), libPath.size()) != 0) {
|
||||
HLOGD("strncpy_s recordMmap failed!");
|
||||
}
|
||||
NeedAdaptSandboxPath(recordMmap.data_.filename, recordMmap.data_.pid, recordMmap.header.size);
|
||||
UpdateThreadMaps(recordMmap.data_.pid, recordMmap.data_.tid, recordMmap.data_.filename,
|
||||
recordMmap.data_.addr, recordMmap.data_.len, recordMmap.data_.pgoff);
|
||||
UpdateSymbols(recordMmap.data_.filename);
|
||||
}
|
||||
}
|
||||
|
||||
bool VirtualRuntime::CheckValidSandBoxMmap(PerfRecordMmap2 &recordMmap2)
|
||||
{
|
||||
static std::shared_ptr<DfxMap> prevMap;
|
||||
if ((recordMmap2.data_.prot & PROT_EXEC) != 0) {
|
||||
// fake first segment, when second segment come.
|
||||
auto symFile = SymbolsFile::CreateSymbolsFile(SYMBOL_ELF_FILE, recordMmap2.data_.filename);
|
||||
if (symFile == nullptr) {
|
||||
HLOGD("CheckValidSandBoxMmap Failed to create symbolFile!");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<DfxMap> curMap;
|
||||
if (strstr(recordMmap2.data_.filename, ".hap") != nullptr) {
|
||||
curMap = std::make_shared<DfxMap>(
|
||||
recordMmap2.data_.addr,
|
||||
recordMmap2.data_.addr + recordMmap2.data_.len,
|
||||
recordMmap2.data_.pgoff,
|
||||
"", // prot
|
||||
recordMmap2.data_.filename
|
||||
);
|
||||
curMap->prevMap = prevMap;
|
||||
}
|
||||
|
||||
if(!symFile->LoadDebugInfo(curMap)) {
|
||||
HLOGD("CheckValidSandBoxMmap Failed to load debuginfo!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!loadSymboleWhenNeeded_) {
|
||||
symFile->LoadSymbols(curMap);
|
||||
}
|
||||
|
||||
if (strstr(recordMmap2.data_.filename, ".hap") == nullptr) {
|
||||
auto elfLoadInfoMap = symFile->GetPtLoads();
|
||||
u64 begin = recordMmap2.data_.addr - elfLoadInfoMap[0].mmapLen;
|
||||
u64 len = elfLoadInfoMap[0].mmapLen;
|
||||
u64 pgoff = elfLoadInfoMap[0].offset & (~(elfLoadInfoMap[0].align - 1));
|
||||
std::unique_ptr<PerfRecordMmap2> mmap2FirstSeg =
|
||||
std::make_unique<PerfRecordMmap2>(recordMmap2.inKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid,
|
||||
begin, len, pgoff, 0, 0, 0, PROT_READ, 0, std::string(recordMmap2.data_.filename));
|
||||
UpdateThreadMaps(mmap2FirstSeg->data_.pid, mmap2FirstSeg->data_.tid, mmap2FirstSeg->data_.filename,
|
||||
mmap2FirstSeg->data_.addr, mmap2FirstSeg->data_.len, mmap2FirstSeg->data_.pgoff);
|
||||
recordCallBack_(std::move(mmap2FirstSeg));
|
||||
} else {
|
||||
auto elfLoadInfoMap = symFile->GetPtLoads();
|
||||
u64 begin = recordMmap2.data_.addr - elfLoadInfoMap[0].mmapLen;
|
||||
u64 len = elfLoadInfoMap[0].mmapLen;
|
||||
u64 pgoff = elfLoadInfoMap[0].offset & (~(elfLoadInfoMap[0].align - 1));
|
||||
std::unique_ptr<PerfRecordMmap2> mmap2FirstSeg =
|
||||
std::make_unique<PerfRecordMmap2>(recordMmap2.inKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid,
|
||||
begin, len, pgoff, 0, 0, 0, PROT_READ, 0, curMap->name);
|
||||
UpdateThreadMaps(mmap2FirstSeg->data_.pid, mmap2FirstSeg->data_.tid, curMap->name,
|
||||
mmap2FirstSeg->data_.addr, mmap2FirstSeg->data_.len, mmap2FirstSeg->data_.pgoff);
|
||||
recordCallBack_(std::move(mmap2FirstSeg));
|
||||
|
||||
std::unique_ptr<PerfRecordMmap2> mmap2SecondSegment =
|
||||
std::make_unique<PerfRecordMmap2>(recordMmap2.inKernel(), recordMmap2.data_.pid, recordMmap2.data_.tid,
|
||||
recordMmap2.data_.addr,
|
||||
recordMmap2.data_.len,
|
||||
recordMmap2.data_.pgoff - prevMap->offset, // minus load offset of hap
|
||||
0, 0, 0, recordMmap2.data_.prot, 0, curMap->name);
|
||||
UpdateThreadMaps(mmap2SecondSegment->data_.pid, mmap2SecondSegment->data_.tid, curMap->name,
|
||||
mmap2SecondSegment->data_.addr, mmap2SecondSegment->data_.len, mmap2SecondSegment->data_.pgoff);
|
||||
recordCallBack_(std::move(mmap2SecondSegment));
|
||||
recordMmap2.discard_ = true;
|
||||
}
|
||||
symbolsFiles_.emplace_back(std::move(symFile));
|
||||
return true;
|
||||
} else if (recordMmap2.data_.pgoff == 0) {
|
||||
recordMmap2.discard_ = true;
|
||||
}
|
||||
|
||||
if (strstr(recordMmap2.data_.filename, ".hap") != nullptr) {
|
||||
prevMap = std::make_shared<DfxMap>(
|
||||
recordMmap2.data_.addr,
|
||||
recordMmap2.data_.addr + recordMmap2.data_.len,
|
||||
recordMmap2.data_.pgoff,
|
||||
"", // prot
|
||||
recordMmap2.data_.filename
|
||||
);
|
||||
HLOGD("CheckValidSandBoxMmap Update prev map!");
|
||||
}
|
||||
return !recordMmap2.discard_;
|
||||
}
|
||||
|
||||
void VirtualRuntime::UpdateFromRecord(PerfRecordMmap2 &recordMmap2)
|
||||
{
|
||||
if (!OHOS::HiviewDFX::DfxMaps::IsLegalMapItem(recordMmap2.data_.filename)) {
|
||||
return;
|
||||
}
|
||||
|
||||
HLOGV(" MMAP2: size %d pid %u tid %u", recordMmap2.header.size, recordMmap2.data_.pid,
|
||||
recordMmap2.data_.tid);
|
||||
HLOGV(" MMAP2: %s dso '%s' (0x%llx-0x%llx)@0x%llx", recordMmap2.inKernel() ? "kernel" : "user",
|
||||
HLOGV(" MMAP2: %s dso '%s' (0x%llx-0x%llx)@0x%llx prot:%u", recordMmap2.inKernel() ? "kernel" : "user",
|
||||
recordMmap2.data_.filename, recordMmap2.data_.addr,
|
||||
recordMmap2.data_.addr + recordMmap2.data_.len, recordMmap2.data_.pgoff);
|
||||
std::string libPath = AdaptSandboxPath(recordMmap2.data_.filename, recordMmap2.data_.pid);
|
||||
recordMmap2.header.size += libPath.size() - strlen(recordMmap2.data_.filename);
|
||||
(void)memset_s(recordMmap2.data_.filename, KILO, '\0', KILO);
|
||||
if (strncpy_s(recordMmap2.data_.filename, KILO, libPath.c_str(), libPath.size()) != 0) {
|
||||
HLOGD("strncpy_s recordMmap2 failed!");
|
||||
recordMmap2.data_.addr + recordMmap2.data_.len, recordMmap2.data_.pgoff, recordMmap2.data_.prot);
|
||||
|
||||
if (recordCallBack_) {
|
||||
if (NeedAdaptSandboxPath(recordMmap2.data_.filename, recordMmap2.data_.pid, recordMmap2.header.size)) {
|
||||
if (!CheckValidSandBoxMmap(recordMmap2)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateThreadMaps(recordMmap2.data_.pid, recordMmap2.data_.tid, recordMmap2.data_.filename,
|
||||
recordMmap2.data_.addr, recordMmap2.data_.len, recordMmap2.data_.pgoff);
|
||||
|
Loading…
Reference in New Issue
Block a user