1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <libelf64/comparator.h>
18 
19 #include <libelf64/elf64.h>
20 
21 #include <cstring>
22 #include <iostream>
23 #include <string>
24 #include <vector>
25 
26 #include <elf.h>
27 
28 namespace android {
29 namespace elf64 {
30 
printEhdrDiff(const std::string & name,unsigned long long hdrField1,unsigned long long hdrField2)31 static void printEhdrDiff(const std::string& name, unsigned long long hdrField1,
32                           unsigned long long hdrField2) {
33     std::cout << "\tDiff ehdr1." << name << " = 0x" << std::hex << hdrField1 << " != " << "ehdr2."
34               << name << " = 0x" << std::hex << hdrField2 << std::endl;
35 }
36 
printFieldDiff(const std::string & strPrefix,const std::string & fieldName,int index,unsigned long long shdrField1,unsigned long long shdrField2)37 static void printFieldDiff(const std::string& strPrefix, const std::string& fieldName, int index,
38                            unsigned long long shdrField1, unsigned long long shdrField2) {
39     std::cout << "\tDiff " << strPrefix << "1[" << index << "]." << fieldName << " = 0x" << std::hex
40               << shdrField1 << " != " << strPrefix << "2[" << index << "]." << fieldName << " = 0x"
41               << std::hex << shdrField2 << std::endl;
42 }
43 
44 // Compares the ELF64 Executable Header.
45 // Returns true if they are equal, otherwise false.
compare(const Elf64_Ehdr & ehdr1,const Elf64_Ehdr & ehdr2)46 bool Elf64Comparator::compare(const Elf64_Ehdr& ehdr1, const Elf64_Ehdr& ehdr2) {
47     bool equal = true;
48 
49     std::cout << "\nComparing ELF64 Executable Headers ..." << std::endl;
50 
51     // Comparing magic number and other info.
52     for (int i = 0; i < EI_NIDENT; i++) {
53         if (ehdr1.e_ident[i] != ehdr2.e_ident[i]) {
54             std::cout << "Diff ehdr1.e_ident[" << std::dec << i << "]=" << ehdr1.e_ident[i]
55                       << " != " << "ehdr2.e_ident[" << i << "]=" << ehdr2.e_ident[i] << std::endl;
56             equal = false;
57         }
58     }
59 
60     if (ehdr1.e_type != ehdr2.e_type) {
61         printEhdrDiff("e_type", ehdr1.e_type, ehdr2.e_type);
62         equal = false;
63     }
64 
65     if (ehdr1.e_machine != ehdr2.e_machine) {
66         printEhdrDiff("e_machine", ehdr1.e_machine, ehdr2.e_machine);
67         equal = false;
68     }
69 
70     if (ehdr1.e_version != ehdr2.e_version) {
71         printEhdrDiff("e_version", ehdr1.e_version, ehdr2.e_version);
72         equal = false;
73     }
74 
75     if (ehdr1.e_entry != ehdr2.e_entry) {
76         printEhdrDiff("e_entry", ehdr1.e_entry, ehdr2.e_entry);
77         equal = false;
78     }
79 
80     if (ehdr1.e_phoff != ehdr2.e_phoff) {
81         printEhdrDiff("e_phoff", ehdr1.e_phoff, ehdr2.e_phoff);
82         equal = false;
83     }
84 
85     if (ehdr1.e_shoff != ehdr2.e_shoff) {
86         printEhdrDiff("e_shoff", ehdr1.e_shoff, ehdr2.e_shoff);
87         equal = false;
88     }
89 
90     if (ehdr1.e_flags != ehdr2.e_flags) {
91         printEhdrDiff("e_flags", ehdr1.e_flags, ehdr2.e_flags);
92         equal = false;
93     }
94 
95     if (ehdr1.e_ehsize != ehdr2.e_ehsize) {
96         printEhdrDiff("e_ehsize", ehdr1.e_ehsize, ehdr2.e_ehsize);
97         equal = false;
98     }
99 
100     if (ehdr1.e_phentsize != ehdr2.e_phentsize) {
101         printEhdrDiff("e_phentsize", ehdr1.e_phentsize, ehdr2.e_phentsize);
102         equal = false;
103     }
104 
105     if (ehdr1.e_phnum != ehdr2.e_phnum) {
106         printEhdrDiff("e_phnum", ehdr1.e_phnum, ehdr2.e_phnum);
107         equal = false;
108     }
109 
110     if (ehdr1.e_shentsize != ehdr2.e_shentsize) {
111         printEhdrDiff("e_shentsize", ehdr1.e_shentsize, ehdr2.e_shentsize);
112         equal = false;
113     }
114 
115     if (ehdr1.e_shnum != ehdr2.e_shnum) {
116         printEhdrDiff("e_shnum", ehdr1.e_shnum, ehdr2.e_shnum);
117         equal = false;
118     }
119 
120     if (ehdr1.e_shstrndx != ehdr2.e_shstrndx) {
121         printEhdrDiff("e_shstrndx", ehdr1.e_shstrndx, ehdr2.e_shstrndx);
122         equal = false;
123     }
124 
125     return equal;
126 }
127 
128 // Compares the ELF64 Program (Segment) Headers.
129 // Returns true if they are equal, otherwise false.
compare(const std::vector<Elf64_Phdr> & phdrs1,const std::vector<Elf64_Phdr> & phdrs2)130 bool Elf64Comparator::compare(const std::vector<Elf64_Phdr>& phdrs1,
131                               const std::vector<Elf64_Phdr>& phdrs2) {
132     bool equal = true;
133 
134     std::cout << "\nComparing ELF64 Program Headers ..." << std::endl;
135 
136     if (phdrs1.size() != phdrs2.size()) {
137         std::cout << "\tDiff phdrs1.size() = " << std::dec << phdrs1.size()
138                   << " != " << "phdrs2.size() = " << phdrs2.size() << std::endl;
139         return false;
140     }
141 
142     for (int i = 0; i < phdrs1.size(); i++) {
143         Elf64_Phdr phdr1 = phdrs1.at(i);
144         Elf64_Phdr phdr2 = phdrs2.at(i);
145 
146         if (phdr1.p_type != phdr2.p_type) {
147             printFieldDiff("phdrs", "p_type", i, phdr1.p_type, phdr2.p_type);
148             equal = false;
149         }
150 
151         if (phdr1.p_flags != phdr2.p_flags) {
152             printFieldDiff("phdrs", "p_flags", i, phdr1.p_flags, phdr2.p_flags);
153             equal = false;
154         }
155 
156         if (phdr1.p_offset != phdr2.p_offset) {
157             printFieldDiff("phdrs", "p_offset", i, phdr1.p_offset, phdr2.p_offset);
158             equal = false;
159         }
160 
161         if (phdr1.p_vaddr != phdr2.p_vaddr) {
162             printFieldDiff("phdrs", "p_vaddr", i, phdr1.p_vaddr, phdr2.p_vaddr);
163             equal = false;
164         }
165 
166         if (phdr1.p_paddr != phdr2.p_paddr) {
167             printFieldDiff("phdrs", "p_paddr", i, phdr1.p_paddr, phdr2.p_paddr);
168             equal = false;
169         }
170 
171         if (phdr1.p_filesz != phdr2.p_filesz) {
172             printFieldDiff("phdrs", "p_filesz", i, phdr1.p_filesz, phdr2.p_filesz);
173             equal = false;
174         }
175 
176         if (phdr1.p_memsz != phdr2.p_memsz) {
177             printFieldDiff("phdrs", "p_memsz", i, phdr1.p_memsz, phdr2.p_memsz);
178             equal = false;
179         }
180 
181         if (phdr1.p_align != phdr2.p_align) {
182             printFieldDiff("phdrs", "p_align", i, phdr1.p_align, phdr2.p_align);
183             equal = false;
184         }
185     }
186 
187     return equal;
188 }
189 
190 // Compares the ELF64 Section Headers.
191 // Returns true if they are equal, otherwise false.
compare(const std::vector<Elf64_Shdr> & shdrs1,const std::vector<Elf64_Shdr> & shdrs2)192 bool Elf64Comparator::compare(const std::vector<Elf64_Shdr>& shdrs1,
193                               const std::vector<Elf64_Shdr>& shdrs2) {
194     bool equal = true;
195 
196     std::cout << "\nComparing ELF64 Section Headers ..." << std::endl;
197 
198     if (shdrs1.size() != shdrs2.size()) {
199         std::cout << "\tDiff shdrs1.size() = " << std::dec << shdrs1.size()
200                   << " != " << "shdrs2.size() = " << shdrs2.size() << std::endl;
201         return false;
202     }
203 
204     for (int i = 0; i < shdrs1.size(); i++) {
205         Elf64_Shdr shdr1 = shdrs1.at(i);
206         Elf64_Shdr shdr2 = shdrs2.at(i);
207 
208         if (shdr1.sh_name != shdr2.sh_name) {
209             printFieldDiff("shdrs", "sh_name", i, shdr1.sh_name, shdr2.sh_name);
210             equal = false;
211         }
212 
213         if (shdr1.sh_type != shdr2.sh_type) {
214             printFieldDiff("shdrs", "sh_type", i, shdr1.sh_type, shdr2.sh_type);
215             equal = false;
216         }
217 
218         if (shdr1.sh_flags != shdr2.sh_flags) {
219             printFieldDiff("shdrs", "sh_flags", i, shdr1.sh_flags, shdr2.sh_flags);
220             equal = false;
221         }
222 
223         if (shdr1.sh_addr != shdr2.sh_addr) {
224             printFieldDiff("shdrs", "sh_addr", i, shdr1.sh_addr, shdr2.sh_addr);
225             equal = false;
226         }
227 
228         if (shdr1.sh_offset != shdr2.sh_offset) {
229             printFieldDiff("shdrs", "sh_offset", i, shdr1.sh_offset, shdr2.sh_offset);
230             equal = false;
231         }
232 
233         if (shdr1.sh_size != shdr2.sh_size) {
234             printFieldDiff("shdrs", "sh_size", i, shdr1.sh_size, shdr2.sh_size);
235             equal = false;
236         }
237 
238         if (shdr1.sh_link != shdr2.sh_link) {
239             printFieldDiff("shdrs", "sh_link", i, shdr1.sh_link, shdr2.sh_link);
240             equal = false;
241         }
242 
243         if (shdr1.sh_info != shdr2.sh_info) {
244             printFieldDiff("shdrs", "sh_info", i, shdr1.sh_info, shdr2.sh_info);
245             equal = false;
246         }
247 
248         if (shdr1.sh_addralign != shdr2.sh_addralign) {
249             printFieldDiff("shdrs", "sh_addralign", i, shdr1.sh_addralign, shdr2.sh_addralign);
250             equal = false;
251         }
252 
253         if (shdr1.sh_entsize != shdr2.sh_entsize) {
254             printFieldDiff("shdrs", "sh_entsize", i, shdr1.sh_entsize, shdr2.sh_entsize);
255             equal = false;
256         }
257     }
258 
259     return equal;
260 }
261 
262 // Compares the ELF64 Section content.
263 // Returns true if they are equal, otherwise false.
compare(const std::vector<Elf64_Sc> & sections1,const std::vector<Elf64_Sc> & sections2)264 bool Elf64Comparator::compare(const std::vector<Elf64_Sc>& sections1,
265                               const std::vector<Elf64_Sc>& sections2) {
266     bool equal = true;
267 
268     std::cout << "\nComparing ELF64 Sections (content) ..." << std::endl;
269 
270     if (sections1.size() != sections2.size()) {
271         std::cout << "\tDiff sections1.size() = " << std::dec << sections1.size()
272                   << " != " << "sections2.size() = " << sections2.size() << std::endl;
273         return false;
274     }
275 
276     for (int i = 0; i < sections1.size(); i++) {
277         if (sections1.at(i).size != sections2.at(i).size) {
278             std::cout << "\tDiff sections1[" << std::dec << i << "].size = " << sections1.at(i).size
279                       << " != " << "sections2[" << i << "].size = " << sections2.at(i).size
280                       << std::endl;
281             equal = false;
282             // If size is different, data is not compared.
283             continue;
284         }
285 
286         if (sections1.at(i).data.empty() && sections2.at(i).data.empty()) {
287             // The .bss section is empty.
288             continue;
289         }
290 
291         if (sections1.at(i).data.empty() || sections2.at(i).data.empty()) {
292             // The index of the .bss section is different for both files.
293             equal = false;
294             continue;
295         }
296 
297         if (sections1.at(i).data != sections2.at(i).data) {
298             std::cout << "\tDiff " << std::dec << "section1[" << i << "].data != " << "section2["
299                       << i << "].data" << std::endl;
300 
301             equal = false;
302         }
303     }
304 
305     return equal;
306 }
307 
308 }  // namespace elf64
309 }  // namespace android
310