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