Line data Source code
1 : /**
2 : * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3 : * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4 : * CANN Open Software License Agreement Version 2.0 (the "License").
5 : * Please refer to the License for details. You may not use this file except in compliance with the License.
6 : * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7 : * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8 : * See LICENSE in the root of the software repository for the full text of the License.
9 : */
10 :
11 : #include "dump_ELF.h"
12 : #include "log/adx_log.h"
13 : #include "mmpa_api.h"
14 :
15 : namespace Adx {
16 : namespace ELF {
17 :
18 : namespace {
19 : constexpr Elf64_Half EM_HIIPU = 0x1029;
20 : constexpr Elf64_Word EV_VERSION = 0x01;
21 : constexpr Elf64_Off ADD_ALIGN = 16;
22 : const std::string STRTAB_SECTION_NAME = ".shstrtab";
23 : } // namespace
24 :
25 377 : Section::Section(Elf64_Word type) { header_.sh_type = type; }
26 :
27 356 : void Section::SetData(std::string& data)
28 : {
29 356 : data_ = std::move(data);
30 356 : header_.sh_size = data_.size();
31 356 : }
32 :
33 84 : void Section::SetAddr(Elf64_Addr addr) { header_.sh_addr = addr; }
34 :
35 769 : void Section::SetOffSet(Elf64_Off offset) { header_.sh_offset = offset; }
36 :
37 113 : void Section::SetEntSize(Elf64_Word entSize) { header_.sh_entsize = entSize; }
38 :
39 376 : void Section::SetNameIndex(Elf64_Word nameIndex) { header_.sh_name = nameIndex; }
40 :
41 208 : void Section::SetLink(Elf64_Word link) { header_.sh_link = link; }
42 :
43 208 : void Section::SetInfo(Elf64_Word info) { header_.sh_info = info; }
44 :
45 376 : void Section::SetIndex(uint32_t index) { index_ = index; }
46 :
47 340 : uint32_t Section::GetIndex() const { return index_; }
48 :
49 769 : void Section::Save(std::ofstream& ofs, std::streampos headerPosition)
50 : {
51 769 : SaveHeader(ofs, headerPosition);
52 769 : SaveData(ofs);
53 769 : }
54 :
55 769 : void Section::SaveHeader(std::ofstream& ofs, std::streampos offset)
56 : {
57 769 : ofs.seekp(offset);
58 769 : ofs.write(reinterpret_cast<const char*>(&header_), sizeof(header_));
59 769 : }
60 :
61 769 : void Section::SaveData(std::ofstream& ofs)
62 : {
63 769 : ofs.seekp(header_.sh_offset);
64 769 : ofs.write(data_.c_str(), data_.size());
65 769 : }
66 :
67 769 : Elf64_Xword Section::GetSize() const { return header_.sh_size; }
68 :
69 2 : void Section::SetAddrAlign(Elf64_Xword addrAlign) { header_.sh_addralign = addrAlign; }
70 :
71 771 : Elf64_Xword Section::GetAddrAlign() const { return header_.sh_addralign; }
72 :
73 18 : DumpELF::DumpELF()
74 : {
75 18 : header_.e_ident[EI_MAG0] = ELFMAG0;
76 18 : header_.e_ident[EI_MAG1] = ELFMAG1;
77 18 : header_.e_ident[EI_MAG2] = ELFMAG2;
78 18 : header_.e_ident[EI_MAG3] = ELFMAG3;
79 18 : header_.e_ident[EI_CLASS] = ELFCLASS64;
80 18 : header_.e_ident[EI_DATA] = ELFDATA2LSB;
81 18 : header_.e_ident[EI_VERSION] = EV_CURRENT;
82 18 : header_.e_ehsize = sizeof(Elf64_Ehdr);
83 18 : header_.e_type = ET_CORE;
84 18 : header_.e_machine = EM_HIIPU;
85 18 : header_.e_version = EV_VERSION;
86 18 : CreateMandatorySection();
87 18 : }
88 :
89 376 : SectionPtr DumpELF::CreateSection(Elf64_Word type)
90 : {
91 : try {
92 376 : sections_.emplace_back(std::make_shared<Section>(type));
93 376 : sections_.back()->SetIndex(static_cast<uint32_t>(sections_.size() - 1));
94 376 : return sections_.back();
95 0 : } catch (std::exception& ex) {
96 0 : IDE_LOGE("Section make shared failed, error=%s", ex.what());
97 0 : return nullptr;
98 0 : }
99 : }
100 :
101 18 : void DumpELF::CreateMandatorySection()
102 : {
103 : // first section is null section
104 18 : SectionPtr sec0 = CreateSection(SHT_NULL);
105 18 : IDE_CTRL_VALUE_FAILED(sec0 != nullptr, return, "Create first NULL section failed");
106 18 : sectionNameStream_ << '\0';
107 18 : sec0->SetNameIndex(0);
108 18 : }
109 :
110 358 : SectionPtr DumpELF::AddSection(Elf64_Word type, const std::string& name)
111 : {
112 358 : SectionPtr newSection = CreateSection(type);
113 358 : if (newSection == nullptr) {
114 0 : return nullptr;
115 : }
116 :
117 358 : Elf64_Word nameIndex = 0;
118 358 : if (sectionNameTable_.find(name) != sectionNameTable_.end()) {
119 273 : nameIndex = sectionNameTable_[name];
120 : } else {
121 85 : nameIndex = sectionNameStream_.tellp();
122 85 : sectionNameStream_ << name << '\0';
123 85 : sectionNameTable_[name] = nameIndex;
124 : }
125 358 : newSection->SetNameIndex(nameIndex);
126 :
127 358 : return newSection;
128 358 : }
129 :
130 209 : SectionPtr DumpELF::GetSectionByIndex(uint32_t index) const
131 : {
132 209 : IDE_CTRL_VALUE_FAILED(
133 : index < sections_.size(), return nullptr, "Get section failed, index %u out of range %u", index,
134 : sections_.size());
135 :
136 208 : return sections_[index];
137 : }
138 :
139 10 : void DumpELF::Save(const std::string& filename)
140 : {
141 10 : IDE_CTRL_VALUE_FAILED(
142 : mmAccess2(filename.c_str(), F_OK) != EN_OK, return, "file %s already exist", filename.c_str());
143 :
144 9 : int32_t fd = mmOpen2(filename.c_str(), M_RDWR | M_CREAT, M_IRUSR | M_IWUSR);
145 9 : IDE_CTRL_VALUE_FAILED(fd >= 0, return, "open file %s failed, strerror=%s", filename.c_str(), strerror(errno));
146 9 : close(fd);
147 :
148 9 : std::ofstream ofs(filename, std::ios::binary);
149 9 : IDE_CTRL_VALUE_FAILED(ofs.is_open(), return, "open file %s failed, strerror=%s", filename.c_str(), strerror(errno));
150 :
151 9 : SetSectionHeaderStringTable();
152 :
153 9 : header_.e_shentsize = sizeof(Elf64_Shdr);
154 9 : header_.e_shnum = sections_.size();
155 :
156 9 : currentFilePos_ = sizeof(Elf64_Ehdr);
157 9 : LayoutSections();
158 9 : LayoutSectionTable();
159 :
160 9 : if (!SaveHeader(ofs)) {
161 0 : IDE_LOGE("Failed to save ELF header");
162 0 : ofs.close();
163 0 : return;
164 : }
165 9 : SaveSections(ofs);
166 :
167 9 : ofs.close();
168 9 : IDE_LOGE("Save dump file %s", filename.c_str());
169 :
170 9 : int32_t err = mmChmod(filename.c_str(), M_IRUSR); // 落盘文件置为最小权限:用户只读, 400
171 9 : IDE_CTRL_VALUE_WARN(err == 0, return, "mmChmod %s failed, strerror=%s", filename.c_str(), strerror(errno));
172 9 : }
173 :
174 9 : void DumpELF::SetSectionHeaderStringTable()
175 : {
176 9 : SectionPtr section = AddSection(SHT_STRTAB, STRTAB_SECTION_NAME);
177 9 : IDE_CTRL_VALUE_WARN(section != nullptr, return, "Create %s section failed.", STRTAB_SECTION_NAME.c_str());
178 9 : std::string data = sectionNameStream_.str();
179 9 : section->SetData(data);
180 9 : header_.e_shstrndx = sections_.size() - 1;
181 9 : }
182 :
183 9 : void DumpELF::LayoutSections()
184 : {
185 787 : for (const auto& section : sections_) {
186 769 : Elf64_Xword sectionAlign = section->GetAddrAlign();
187 769 : if ((sectionAlign > 1) && (currentFilePos_ % sectionAlign != 0)) {
188 0 : currentFilePos_ += sectionAlign - (currentFilePos_ % sectionAlign);
189 : }
190 769 : section->SetOffSet(currentFilePos_);
191 769 : currentFilePos_ += section->GetSize();
192 : }
193 9 : }
194 :
195 9 : void DumpELF::LayoutSectionTable()
196 : {
197 9 : if (currentFilePos_ % ADD_ALIGN != 0) {
198 9 : currentFilePos_ += ADD_ALIGN - (currentFilePos_ % ADD_ALIGN);
199 : }
200 9 : header_.e_shoff = currentFilePos_;
201 9 : }
202 :
203 9 : bool DumpELF::SaveHeader(std::ofstream& ofs) const
204 : {
205 9 : ofs.seekp(0);
206 9 : ofs.write(reinterpret_cast<const char*>(&header_), sizeof(header_));
207 9 : return ofs.good();
208 : }
209 :
210 9 : void DumpELF::SaveSections(std::ofstream& ofs)
211 : {
212 778 : for (uint32_t i = 0; i < sections_.size(); ++i) {
213 769 : std::streampos headerPosition = header_.e_shoff + i * sizeof(Elf64_Shdr);
214 769 : sections_[i]->Save(ofs, headerPosition);
215 769 : IDE_CTRL_VALUE_FAILED_NODO(ofs.good(), continue, "save section %u failed", i);
216 : }
217 9 : }
218 :
219 : } // namespace ELF
220 : } // namespace Adx
|