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