1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
// int_encoding.cc -- variable length and unaligned integer encoding support.
// Copyright (C) 2009-2020 Free Software Foundation, Inc.
// Written by Doug Kwan <dougkwan@google.com> by refactoring scattered
// contents from other files in gold. Original code written by Ian
// Lance Taylor <iant@google.com> and Caleb Howe <cshowe@google.com>.
// This file is part of gold.
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
// MA 02110-1301, USA.
#include "gold.h"
#include <vector>
#include "int_encoding.h"
namespace gold {
// Read an unsigned LEB128 number. Each byte contains 7 bits of
// information, plus one bit saying whether the number continues or
// not. BYTE contains the first byte of the number, and is guaranteed
// to have the continuation bit set.
uint64_t
read_unsigned_LEB_128_x(const unsigned char* buffer, size_t* len,
unsigned char byte)
{
uint64_t result = static_cast<uint64_t>(byte & 0x7f);
size_t num_read = 1;
unsigned int shift = 7;
do
{
if (num_read > 64 / 7 + 1)
{
gold_warning(_("Unusually large LEB128 decoded, "
"debug information may be corrupted"));
break;
}
byte = *buffer++;
num_read++;
result |= (static_cast<uint64_t>(byte & 0x7f)) << shift;
shift += 7;
}
while (byte & 0x80);
*len = num_read;
return result;
}
// Read a signed LEB128 number. These are like regular LEB128
// numbers, except the last byte may have a sign bit set.
// BYTE contains the first byte of the number, and is guaranteed
// to have the continuation bit set.
int64_t
read_signed_LEB_128_x(const unsigned char* buffer, size_t* len,
unsigned char byte)
{
int64_t result = static_cast<uint64_t>(byte & 0x7f);
int shift = 7;
size_t num_read = 1;
do
{
if (num_read > 64 / 7 + 1)
{
gold_warning(_("Unusually large LEB128 decoded, "
"debug information may be corrupted"));
break;
}
byte = *buffer++;
num_read++;
result |= (static_cast<uint64_t>(byte & 0x7f) << shift);
shift += 7;
}
while (byte & 0x80);
if ((shift < 8 * static_cast<int>(sizeof(result))) && (byte & 0x40))
result |= -((static_cast<int64_t>(1)) << shift);
*len = num_read;
return result;
}
void
write_unsigned_LEB_128(std::vector<unsigned char>* buffer, uint64_t value)
{
do
{
unsigned char current_byte = value & 0x7f;
value >>= 7;
if (value != 0)
{
current_byte |= 0x80;
}
buffer->push_back(current_byte);
}
while (value != 0);
}
size_t
get_length_as_unsigned_LEB_128(uint64_t value)
{
size_t length = 0;
do
{
unsigned char current_byte = value & 0x7f;
value >>= 7;
if (value != 0)
{
current_byte |= 0x80;
}
length++;
}
while (value != 0);
return length;
}
} // End namespace gold.
|