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