1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "LineNumberProgram.h" 7 8 #include <algorithm> 9 10 #include <stdio.h> 11 #include <string.h> 12 13 #include "Dwarf.h" 14 #include "Tracing.h" 15 16 17 static const uint8 kLineNumberStandardOpcodeOperands[] 18 = { 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 }; 19 static const uint32 kLineNumberStandardOpcodeCount = 12; 20 21 22 LineNumberProgram::LineNumberProgram(uint8 addressSize, bool isBigEndian) 23 : 24 fProgram(NULL), 25 fProgramSize(0), 26 fMinInstructionLength(0), 27 fDefaultIsStatement(0), 28 fLineBase(0), 29 fLineRange(0), 30 fOpcodeBase(0), 31 fAddressSize(addressSize), 32 fIsBigEndian(isBigEndian), 33 fStandardOpcodeLengths(NULL) 34 { 35 } 36 37 38 LineNumberProgram::~LineNumberProgram() 39 { 40 } 41 42 43 status_t 44 LineNumberProgram::Init(const void* program, size_t programSize, 45 uint8 minInstructionLength, bool defaultIsStatement, int8 lineBase, 46 uint8 lineRange, uint8 opcodeBase, const uint8* standardOpcodeLengths) 47 { 48 // first check the operand counts for the standard opcodes 49 uint8 standardOpcodeCount = std::min((uint32)opcodeBase - 1, 50 kLineNumberStandardOpcodeCount); 51 for (uint8 i = 0; i < standardOpcodeCount; i++) { 52 if (standardOpcodeLengths[i] != kLineNumberStandardOpcodeOperands[i]) { 53 WARNING("operand count for standard opcode %u does not what we " 54 "expect\n", i + 1); 55 return B_BAD_DATA; 56 } 57 } 58 59 fProgram = program; 60 fProgramSize = programSize; 61 fMinInstructionLength = minInstructionLength; 62 fDefaultIsStatement = defaultIsStatement; 63 fLineBase = lineBase; 64 fLineRange = lineRange; 65 fOpcodeBase = opcodeBase; 66 fStandardOpcodeLengths = standardOpcodeLengths; 67 68 return B_OK; 69 } 70 71 72 void 73 LineNumberProgram::GetInitialState(State& state) const 74 { 75 if (!IsValid()) 76 return; 77 78 _SetToInitial(state); 79 state.dataReader.SetTo(fProgram, fProgramSize, fAddressSize, fIsBigEndian); 80 } 81 82 83 bool 84 LineNumberProgram::GetNextRow(State& state) const 85 { 86 if (state.isSequenceEnd) 87 _SetToInitial(state); 88 89 DataReader& dataReader = state.dataReader; 90 91 while (dataReader.BytesRemaining() > 0) { 92 bool appendRow = false; 93 uint8 opcode = dataReader.Read<uint8>(0); 94 if (opcode >= fOpcodeBase) { 95 // special opcode 96 uint adjustedOpcode = opcode - fOpcodeBase; 97 state.address += (adjustedOpcode / fLineRange) 98 * fMinInstructionLength; 99 state.line += adjustedOpcode % fLineRange + fLineBase; 100 state.isBasicBlock = false; 101 state.isPrologueEnd = false; 102 state.isEpilogueBegin = false; 103 state.discriminator = 0; 104 appendRow = true; 105 } else if (opcode > 0) { 106 // standard opcode 107 switch (opcode) { 108 case DW_LNS_copy: 109 state.isBasicBlock = false; 110 state.isPrologueEnd = false; 111 state.isEpilogueBegin = false; 112 appendRow = true; 113 state.discriminator = 0; 114 break; 115 case DW_LNS_advance_pc: 116 state.address += dataReader.ReadUnsignedLEB128(0) 117 * fMinInstructionLength; 118 break; 119 case DW_LNS_advance_line: 120 state.line += dataReader.ReadSignedLEB128(0); 121 break; 122 case DW_LNS_set_file: 123 state.file = dataReader.ReadUnsignedLEB128(0); 124 break; 125 case DW_LNS_set_column: 126 state.column = dataReader.ReadUnsignedLEB128(0); 127 break; 128 case DW_LNS_negate_stmt: 129 state.isStatement = !state.isStatement; 130 break; 131 case DW_LNS_set_basic_block: 132 state.isBasicBlock = true; 133 break; 134 case DW_LNS_const_add_pc: 135 state.address += ((255 - fOpcodeBase) / fLineRange) 136 * fMinInstructionLength; 137 break; 138 case DW_LNS_fixed_advance_pc: 139 state.address += dataReader.Read<uint16>(0); 140 break; 141 case DW_LNS_set_prologue_end: 142 state.isPrologueEnd = true; 143 break; 144 case DW_LNS_set_epilogue_begin: 145 state.isEpilogueBegin = true; 146 break; 147 case DW_LNS_set_isa: 148 state.instructionSet = dataReader.ReadUnsignedLEB128(0); 149 break; 150 default: 151 WARNING("unsupported standard opcode %u\n", opcode); 152 for (int32 i = 0; i < fStandardOpcodeLengths[opcode - 1]; 153 i++) { 154 dataReader.ReadUnsignedLEB128(0); 155 } 156 } 157 } else { 158 // extended opcode 159 uint32 instructionLength = dataReader.ReadUnsignedLEB128(0); 160 off_t instructionOffset = dataReader.Offset(); 161 uint8 extendedOpcode = dataReader.Read<uint8>(0); 162 163 switch (extendedOpcode) { 164 case DW_LNE_end_sequence: 165 state.isSequenceEnd = true; 166 appendRow = true; 167 break; 168 case DW_LNE_set_address: 169 state.address = dataReader.ReadAddress(0); 170 break; 171 case DW_LNE_define_file: 172 { 173 state.explicitFile = dataReader.ReadString(); 174 state.explicitFileDirIndex 175 = dataReader.ReadUnsignedLEB128(0); 176 dataReader.ReadUnsignedLEB128(0); // modification time 177 dataReader.ReadUnsignedLEB128(0); // file length 178 state.file = -1; 179 break; 180 } 181 case DW_LNE_set_discriminator: 182 { 183 state.discriminator = dataReader.ReadUnsignedLEB128(0); 184 break; 185 } 186 default: 187 WARNING("unsupported extended opcode: %u\n", 188 extendedOpcode); 189 break; 190 } 191 192 dataReader.Skip(instructionLength 193 - (dataReader.Offset() - instructionOffset)); 194 } 195 196 if (dataReader.HasOverflow()) 197 return false; 198 199 if (appendRow) 200 return true; 201 } 202 203 return false; 204 } 205 206 207 void 208 LineNumberProgram::_SetToInitial(State& state) const 209 { 210 state.address = 0; 211 state.file = 1; 212 state.line = 1; 213 state.column = 0; 214 state.isStatement = fDefaultIsStatement; 215 state.isBasicBlock = false; 216 state.isSequenceEnd = false; 217 state.isPrologueEnd = false; 218 state.isEpilogueBegin = false; 219 state.instructionSet = 0; 220 state.discriminator = 0; 221 } 222