1*68d75effSDimitry Andric //===-- stack_trace_compressor.cpp ------------------------------*- C++ -*-===//
2*68d75effSDimitry Andric //
3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*68d75effSDimitry Andric //
7*68d75effSDimitry Andric //===----------------------------------------------------------------------===//
8*68d75effSDimitry Andric
9*68d75effSDimitry Andric #include "gwp_asan/stack_trace_compressor.h"
10*68d75effSDimitry Andric
11*68d75effSDimitry Andric namespace gwp_asan {
12*68d75effSDimitry Andric namespace compression {
13*68d75effSDimitry Andric namespace {
14*68d75effSDimitry Andric // Encodes `Value` as a variable-length integer to `Out`. Returns zero if there
15*68d75effSDimitry Andric // was not enough space in the output buffer to write the complete varInt.
16*68d75effSDimitry Andric // Otherwise returns the length of the encoded integer.
varIntEncode(uintptr_t Value,uint8_t * Out,size_t OutLen)17*68d75effSDimitry Andric size_t varIntEncode(uintptr_t Value, uint8_t *Out, size_t OutLen) {
18*68d75effSDimitry Andric for (size_t i = 0; i < OutLen; ++i) {
19*68d75effSDimitry Andric Out[i] = Value & 0x7f;
20*68d75effSDimitry Andric Value >>= 7;
21*68d75effSDimitry Andric if (!Value)
22*68d75effSDimitry Andric return i + 1;
23*68d75effSDimitry Andric
24*68d75effSDimitry Andric Out[i] |= 0x80;
25*68d75effSDimitry Andric }
26*68d75effSDimitry Andric
27*68d75effSDimitry Andric return 0;
28*68d75effSDimitry Andric }
29*68d75effSDimitry Andric
30*68d75effSDimitry Andric // Decodes a variable-length integer to `Out`. Returns zero if the integer was
31*68d75effSDimitry Andric // too large to be represented in a uintptr_t, or if the input buffer finished
32*68d75effSDimitry Andric // before the integer was decoded (either case meaning that the `In` does not
33*68d75effSDimitry Andric // point to a valid varInt buffer). Otherwise, returns the number of bytes that
34*68d75effSDimitry Andric // were used to store the decoded integer.
varIntDecode(const uint8_t * In,size_t InLen,uintptr_t * Out)35*68d75effSDimitry Andric size_t varIntDecode(const uint8_t *In, size_t InLen, uintptr_t *Out) {
36*68d75effSDimitry Andric *Out = 0;
37*68d75effSDimitry Andric uint8_t Shift = 0;
38*68d75effSDimitry Andric
39*68d75effSDimitry Andric for (size_t i = 0; i < InLen; ++i) {
40*68d75effSDimitry Andric *Out |= (static_cast<uintptr_t>(In[i]) & 0x7f) << Shift;
41*68d75effSDimitry Andric
42*68d75effSDimitry Andric if (In[i] < 0x80)
43*68d75effSDimitry Andric return i + 1;
44*68d75effSDimitry Andric
45*68d75effSDimitry Andric Shift += 7;
46*68d75effSDimitry Andric
47*68d75effSDimitry Andric // Disallow overflowing the range of the output integer.
48*68d75effSDimitry Andric if (Shift >= sizeof(uintptr_t) * 8)
49*68d75effSDimitry Andric return 0;
50*68d75effSDimitry Andric }
51*68d75effSDimitry Andric return 0;
52*68d75effSDimitry Andric }
53*68d75effSDimitry Andric
zigzagEncode(uintptr_t Value)54*68d75effSDimitry Andric uintptr_t zigzagEncode(uintptr_t Value) {
55*68d75effSDimitry Andric uintptr_t Encoded = Value << 1;
56*68d75effSDimitry Andric if (static_cast<intptr_t>(Value) >= 0)
57*68d75effSDimitry Andric return Encoded;
58*68d75effSDimitry Andric return ~Encoded;
59*68d75effSDimitry Andric }
60*68d75effSDimitry Andric
zigzagDecode(uintptr_t Value)61*68d75effSDimitry Andric uintptr_t zigzagDecode(uintptr_t Value) {
62*68d75effSDimitry Andric uintptr_t Decoded = Value >> 1;
63*68d75effSDimitry Andric if (!(Value & 1))
64*68d75effSDimitry Andric return Decoded;
65*68d75effSDimitry Andric return ~Decoded;
66*68d75effSDimitry Andric }
67*68d75effSDimitry Andric } // anonymous namespace
68*68d75effSDimitry Andric
pack(const uintptr_t * Unpacked,size_t UnpackedSize,uint8_t * Packed,size_t PackedMaxSize)69*68d75effSDimitry Andric size_t pack(const uintptr_t *Unpacked, size_t UnpackedSize, uint8_t *Packed,
70*68d75effSDimitry Andric size_t PackedMaxSize) {
71*68d75effSDimitry Andric size_t Index = 0;
72*68d75effSDimitry Andric for (size_t CurrentDepth = 0; CurrentDepth < UnpackedSize; CurrentDepth++) {
73*68d75effSDimitry Andric uintptr_t Diff = Unpacked[CurrentDepth];
74*68d75effSDimitry Andric if (CurrentDepth > 0)
75*68d75effSDimitry Andric Diff -= Unpacked[CurrentDepth - 1];
76*68d75effSDimitry Andric size_t EncodedLength =
77*68d75effSDimitry Andric varIntEncode(zigzagEncode(Diff), Packed + Index, PackedMaxSize - Index);
78*68d75effSDimitry Andric if (!EncodedLength)
79*68d75effSDimitry Andric break;
80*68d75effSDimitry Andric
81*68d75effSDimitry Andric Index += EncodedLength;
82*68d75effSDimitry Andric }
83*68d75effSDimitry Andric
84*68d75effSDimitry Andric return Index;
85*68d75effSDimitry Andric }
86*68d75effSDimitry Andric
unpack(const uint8_t * Packed,size_t PackedSize,uintptr_t * Unpacked,size_t UnpackedMaxSize)87*68d75effSDimitry Andric size_t unpack(const uint8_t *Packed, size_t PackedSize, uintptr_t *Unpacked,
88*68d75effSDimitry Andric size_t UnpackedMaxSize) {
89*68d75effSDimitry Andric size_t CurrentDepth;
90*68d75effSDimitry Andric size_t Index = 0;
91*68d75effSDimitry Andric for (CurrentDepth = 0; CurrentDepth < UnpackedMaxSize; CurrentDepth++) {
92*68d75effSDimitry Andric uintptr_t EncodedDiff;
93*68d75effSDimitry Andric size_t DecodedLength =
94*68d75effSDimitry Andric varIntDecode(Packed + Index, PackedSize - Index, &EncodedDiff);
95*68d75effSDimitry Andric if (!DecodedLength)
96*68d75effSDimitry Andric break;
97*68d75effSDimitry Andric Index += DecodedLength;
98*68d75effSDimitry Andric
99*68d75effSDimitry Andric Unpacked[CurrentDepth] = zigzagDecode(EncodedDiff);
100*68d75effSDimitry Andric if (CurrentDepth > 0)
101*68d75effSDimitry Andric Unpacked[CurrentDepth] += Unpacked[CurrentDepth - 1];
102*68d75effSDimitry Andric }
103*68d75effSDimitry Andric
104*68d75effSDimitry Andric if (Index != PackedSize && CurrentDepth != UnpackedMaxSize)
105*68d75effSDimitry Andric return 0;
106*68d75effSDimitry Andric
107*68d75effSDimitry Andric return CurrentDepth;
108*68d75effSDimitry Andric }
109*68d75effSDimitry Andric
110*68d75effSDimitry Andric } // namespace compression
111*68d75effSDimitry Andric } // namespace gwp_asan
112