#include "gwp_asan/stack_trace_compressor.h"
namespace gwp_asan {
namespace compression {
namespace {
size_t varIntEncode(uintptr_t Value, uint8_t *Out, size_t OutLen) {
for (size_t i = 0; i < OutLen; ++i) {
Out[i] = Value & 0x7f;
Value >>= 7;
if (!Value)
return i + 1;
Out[i] |= 0x80;
}
return 0;
}
size_t varIntDecode(const uint8_t *In, size_t InLen, uintptr_t *Out) {
*Out = 0;
uint8_t Shift = 0;
for (size_t i = 0; i < InLen; ++i) {
*Out |= (static_cast<uintptr_t>(In[i]) & 0x7f) << Shift;
if (In[i] < 0x80)
return i + 1;
Shift += 7;
if (Shift >= sizeof(uintptr_t) * 8)
return 0;
}
return 0;
}
uintptr_t zigzagEncode(uintptr_t Value) {
uintptr_t Encoded = Value << 1;
if (static_cast<intptr_t>(Value) >= 0)
return Encoded;
return ~Encoded;
}
uintptr_t zigzagDecode(uintptr_t Value) {
uintptr_t Decoded = Value >> 1;
if (!(Value & 1))
return Decoded;
return ~Decoded;
}
}
size_t pack(const uintptr_t *Unpacked, size_t UnpackedSize, uint8_t *Packed,
size_t PackedMaxSize) {
size_t Index = 0;
for (size_t CurrentDepth = 0; CurrentDepth < UnpackedSize; CurrentDepth++) {
uintptr_t Diff = Unpacked[CurrentDepth];
if (CurrentDepth > 0)
Diff -= Unpacked[CurrentDepth - 1];
size_t EncodedLength =
varIntEncode(zigzagEncode(Diff), Packed + Index, PackedMaxSize - Index);
if (!EncodedLength)
break;
Index += EncodedLength;
}
return Index;
}
size_t unpack(const uint8_t *Packed, size_t PackedSize, uintptr_t *Unpacked,
size_t UnpackedMaxSize) {
size_t CurrentDepth;
size_t Index = 0;
for (CurrentDepth = 0; CurrentDepth < UnpackedMaxSize; CurrentDepth++) {
uintptr_t EncodedDiff;
size_t DecodedLength =
varIntDecode(Packed + Index, PackedSize - Index, &EncodedDiff);
if (!DecodedLength)
break;
Index += DecodedLength;
Unpacked[CurrentDepth] = zigzagDecode(EncodedDiff);
if (CurrentDepth > 0)
Unpacked[CurrentDepth] += Unpacked[CurrentDepth - 1];
}
if (Index != PackedSize && CurrentDepth != UnpackedMaxSize)
return 0;
return CurrentDepth;
}
}
}