vfs: check userland buffers before reading them.
[haiku.git] / src / kits / debugger / dwarf / LineNumberProgram.cpp
blob922e2e25072f2109271e04c2db2f0334dada03cc
1 /*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
6 #include "LineNumberProgram.h"
8 #include <algorithm>
10 #include <stdio.h>
11 #include <string.h>
13 #include "Dwarf.h"
14 #include "Tracing.h"
17 static const uint8 kLineNumberStandardOpcodeOperands[]
18 = { 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 };
19 static const uint32 kLineNumberStandardOpcodeCount = 12;
22 LineNumberProgram::LineNumberProgram(uint8 addressSize)
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)
37 LineNumberProgram::~LineNumberProgram()
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)
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;
58 fProgram = program;
59 fProgramSize = programSize;
60 fMinInstructionLength = minInstructionLength;
61 fDefaultIsStatement = defaultIsStatement;
62 fLineBase = lineBase;
63 fLineRange = lineRange;
64 fOpcodeBase = opcodeBase;
65 fStandardOpcodeLengths = standardOpcodeLengths;
67 return B_OK;
71 void
72 LineNumberProgram::GetInitialState(State& state) const
74 if (!IsValid())
75 return;
77 _SetToInitial(state);
78 state.dataReader.SetTo(fProgram, fProgramSize, fAddressSize);
82 bool
83 LineNumberProgram::GetNextRow(State& state) const
85 if (state.isSequenceEnd)
86 _SetToInitial(state);
88 DataReader& dataReader = state.dataReader;
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);
156 } else {
157 // extended opcode
158 uint32 instructionLength = dataReader.ReadUnsignedLEB128(0);
159 off_t instructionOffset = dataReader.Offset();
160 uint8 extendedOpcode = dataReader.Read<uint8>(0);
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:
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;
180 case DW_LNE_set_discriminator:
182 state.discriminator = dataReader.ReadUnsignedLEB128(0);
183 break;
185 default:
186 WARNING("unsupported extended opcode: %u\n",
187 extendedOpcode);
188 break;
191 dataReader.Skip(instructionLength
192 - (dataReader.Offset() - instructionOffset));
195 if (dataReader.HasOverflow())
196 return false;
198 if (appendRow)
199 return true;
202 return false;
206 void
207 LineNumberProgram::_SetToInitial(State& state) const
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;