| 195 | |
| 196 | |
| 197 | std::vector<CoverageRegion> readLLVMCoverageMapping(const char * binary_path) |
| 198 | { |
| 199 | std::vector<CoverageRegion> result; |
| 200 | |
| 201 | const int fd = ::open(binary_path, O_RDONLY | O_CLOEXEC); |
| 202 | if (fd < 0) |
| 203 | return result; |
| 204 | |
| 205 | struct stat st; |
| 206 | if (::fstat(fd, &st) < 0) |
| 207 | { |
| 208 | [[maybe_unused]] int err = ::close(fd); |
| 209 | return result; |
| 210 | } |
| 211 | |
| 212 | const size_t size = static_cast<size_t>(st.st_size); |
| 213 | void * mapped = ::mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0); |
| 214 | [[maybe_unused]] int err = ::close(fd); /// mmap keeps the mapping valid after close |
| 215 | if (mapped == MAP_FAILED) |
| 216 | return result; |
| 217 | |
| 218 | const uint8_t * const base = static_cast<const uint8_t *>(mapped); |
| 219 | |
| 220 | auto cleanup = [&] |
| 221 | { |
| 222 | ::munmap(mapped, size); |
| 223 | }; |
| 224 | |
| 225 | /// Validate ELF magic and class (64-bit only). |
| 226 | if (size < sizeof(Elf64_Ehdr) |
| 227 | || memcmp(base, ELFMAG, SELFMAG) != 0 |
| 228 | || base[EI_CLASS] != ELFCLASS64) |
| 229 | { |
| 230 | cleanup(); |
| 231 | return result; |
| 232 | } |
| 233 | |
| 234 | const Elf64_Ehdr * const elf = reinterpret_cast<const Elf64_Ehdr *>(base); |
| 235 | |
| 236 | if (elf->e_shoff == 0 |
| 237 | || elf->e_shstrndx == SHN_UNDEF |
| 238 | || elf->e_shstrndx >= elf->e_shnum) |
| 239 | { |
| 240 | cleanup(); |
| 241 | return result; |
| 242 | } |
| 243 | |
| 244 | /// Bounds check: verify section header table fits in the file. |
| 245 | if (elf->e_shoff + static_cast<size_t>(elf->e_shnum) * sizeof(Elf64_Shdr) > size) |
| 246 | { |
| 247 | cleanup(); |
| 248 | return result; |
| 249 | } |
| 250 | |
| 251 | const Elf64_Shdr * const shdrs = |
| 252 | reinterpret_cast<const Elf64_Shdr *>(base + elf->e_shoff); |
| 253 | |
| 254 | /// Bounds check: verify the string table section offset is within the file. |
no test coverage detected