1 // varint.cc -- variable length and unaligned integer encoding support. 2 3 // Copyright 2009 Free Software Foundation, Inc. 4 // Written by Doug Kwan <dougkwan@google.com> by refactoring scattered 5 // contents from other files in gold. Original code written by Ian 6 // Lance Taylor <iant@google.com> and Caleb Howe <cshowe@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. 36 37 uint64_t 38 read_unsigned_LEB_128(const unsigned char* buffer, size_t* len) 39 { 40 uint64_t result = 0; 41 size_t num_read = 0; 42 unsigned int shift = 0; 43 unsigned char byte; 44 45 do 46 { 47 if (num_read >= 64 / 7) 48 { 49 gold_warning(_("Unusually large LEB128 decoded, " 50 "debug information may be corrupted")); 51 break; 52 } 53 byte = *buffer++; 54 num_read++; 55 result |= (static_cast<uint64_t>(byte & 0x7f)) << shift; 56 shift += 7; 57 } 58 while (byte & 0x80); 59 60 *len = num_read; 61 62 return result; 63 } 64 65 // Read a signed LEB128 number. These are like regular LEB128 66 // numbers, except the last byte may have a sign bit set. 67 68 int64_t 69 read_signed_LEB_128(const unsigned char* buffer, size_t* len) 70 { 71 int64_t result = 0; 72 int shift = 0; 73 size_t num_read = 0; 74 unsigned char byte; 75 76 do 77 { 78 if (num_read >= 64 / 7) 79 { 80 gold_warning(_("Unusually large LEB128 decoded, " 81 "debug information may be corrupted")); 82 break; 83 } 84 byte = *buffer++; 85 num_read++; 86 result |= (static_cast<uint64_t>(byte & 0x7f) << shift); 87 shift += 7; 88 } 89 while (byte & 0x80); 90 91 if ((shift < 8 * static_cast<int>(sizeof(result))) && (byte & 0x40)) 92 result |= -((static_cast<int64_t>(1)) << shift); 93 *len = num_read; 94 return result; 95 } 96 97 void 98 write_unsigned_LEB_128(std::vector<unsigned char>* buffer, uint64_t value) 99 { 100 do 101 { 102 unsigned char current_byte = value & 0x7f; 103 value >>= 7; 104 if (value != 0) 105 { 106 current_byte |= 0x80; 107 } 108 buffer->push_back(current_byte); 109 } 110 while (value != 0); 111 } 112 113 size_t 114 get_length_as_unsigned_LEB_128(uint64_t value) 115 { 116 size_t length = 0; 117 do 118 { 119 unsigned char current_byte = value & 0x7f; 120 value >>= 7; 121 if (value != 0) 122 { 123 current_byte |= 0x80; 124 } 125 length++; 126 } 127 while (value != 0); 128 return length; 129 } 130 131 } // End namespace gold. 132