// int_encoding.cc -- variable length and unaligned integer encoding support. // Copyright (C) 2009-2015 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.