xref: /haiku/src/kits/debugger/dwarf/LineNumberProgram.cpp (revision 4c07199d8201fcf267e90be0d24b76799d03cea6)
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