GCC Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 100.0% 34 / 0 / 34
Functions: 100.0% 3 / 0 / 3
Branches: 100.0% 16 / 0 / 16

src/x86_decode.hpp
Line Branch Exec Source
1 #ifndef DETOURMODKIT_X86_DECODE_HPP
2 #define DETOURMODKIT_X86_DECODE_HPP
3
4 #include "DetourModKit/memory.hpp"
5
6 #include <cstdint>
7 #include <cstring>
8 #include <optional>
9
10 namespace DetourModKit::detail
11 {
12 [[nodiscard]] inline std::optional<std::uintptr_t>
13 7 decode_e9_rel32(std::uintptr_t address) noexcept
14 {
15
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 6 times.
7 if (!Memory::is_readable(reinterpret_cast<const void *>(address), 5))
16 {
17 1 return std::nullopt;
18 }
19 6 const auto *bytes = reinterpret_cast<const std::uint8_t *>(address);
20
2/2
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 5 times.
6 if (bytes[0] != 0xE9)
21 {
22 1 return std::nullopt;
23 }
24 5 std::int32_t disp = 0;
25 5 std::memcpy(&disp, bytes + 1, sizeof(disp));
26 5 return static_cast<std::uintptr_t>(
27 5 static_cast<std::int64_t>(address) + 5 + disp);
28 }
29
30 [[nodiscard]] inline std::optional<std::uintptr_t>
31 4 decode_eb_rel8(std::uintptr_t address) noexcept
32 {
33
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 3 times.
4 if (!Memory::is_readable(reinterpret_cast<const void *>(address), 2))
34 {
35 1 return std::nullopt;
36 }
37 3 const auto *bytes = reinterpret_cast<const std::uint8_t *>(address);
38
2/2
✓ Branch 5 → 6 taken 1 time.
✓ Branch 5 → 7 taken 2 times.
3 if (bytes[0] != 0xEB)
39 {
40 1 return std::nullopt;
41 }
42 2 const auto disp = static_cast<std::int8_t>(bytes[1]);
43 2 return static_cast<std::uintptr_t>(
44 2 static_cast<std::int64_t>(address) + 2 + disp);
45 }
46
47 // FF 25 disp32 on x86-64 is RIP-relative: the 32-bit signed displacement
48 // is added to the address of the next instruction. On x86 (32-bit) the
49 // same encoding is absolute, which this decoder does not handle.
50 [[nodiscard]] inline std::optional<std::uintptr_t>
51 5 decode_ff25_indirect(std::uintptr_t address) noexcept
52 {
53 static_assert(sizeof(void *) == 8,
54 "decode_ff25_indirect assumes x86-64 RIP-relative semantics");
55
2/2
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 4 times.
5 if (!Memory::is_readable(reinterpret_cast<const void *>(address), 6))
56 {
57 1 return std::nullopt;
58 }
59 4 const auto *bytes = reinterpret_cast<const std::uint8_t *>(address);
60
4/4
✓ Branch 5 → 6 taken 3 times.
✓ Branch 5 → 7 taken 1 time.
✓ Branch 6 → 7 taken 1 time.
✓ Branch 6 → 8 taken 2 times.
4 if (bytes[0] != 0xFF || bytes[1] != 0x25)
61 {
62 2 return std::nullopt;
63 }
64 2 std::int32_t disp = 0;
65 2 std::memcpy(&disp, bytes + 2, sizeof(disp));
66 2 const auto slot_addr = static_cast<std::uintptr_t>(
67 2 static_cast<std::int64_t>(address) + 6 + disp);
68
2/2
✓ Branch 9 → 10 taken 1 time.
✓ Branch 9 → 11 taken 1 time.
2 if (!Memory::is_readable(reinterpret_cast<const void *>(slot_addr), sizeof(std::uintptr_t)))
69 {
70 1 return std::nullopt;
71 }
72 1 std::uintptr_t indirect_destination = 0;
73 1 std::memcpy(&indirect_destination,
74 reinterpret_cast<const void *>(slot_addr),
75 sizeof(indirect_destination));
76 1 return indirect_destination;
77 }
78 } // namespace DetourModKit::detail
79
80 #endif // DETOURMODKIT_X86_DECODE_HPP
81