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