1/*
2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2013, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "DwarfExpressionEvaluator.h"
9
10#include <stdio.h>
11#include <stdlib.h>
12
13#include <algorithm>
14#include <new>
15
16#include <Variant.h>
17
18#include "DataReader.h"
19#include "Dwarf.h"
20#include "DwarfTargetInterface.h"
21#include "Tracing.h"
22#include "ValueLocation.h"
23
24
25// number of elements to increase the stack capacity when the stack is full
26static const size_t kStackCapacityIncrement = 64;
27
28// maximum number of elements we allow to be pushed on the stack
29static const size_t kMaxStackCapacity			= 1024;
30
31// maximum number of operations we allow to be performed for a single expression
32// (to avoid running infinite loops forever)
33static const uint32 kMaxOperationCount			= 10000;
34
35
36// #pragma mark - DwarfExpressionEvaluationContext
37
38
39DwarfExpressionEvaluationContext::DwarfExpressionEvaluationContext(
40	const DwarfTargetInterface* targetInterface, uint8 addressSize,
41	bool isBigEndian, target_addr_t relocationDelta)
42	:
43	fTargetInterface(targetInterface),
44	fAddressSize(addressSize),
45	fIsBigEndian(isBigEndian),
46	fRelocationDelta(relocationDelta)
47{
48}
49
50
51DwarfExpressionEvaluationContext::~DwarfExpressionEvaluationContext()
52{
53}
54
55
56// #pragma mark - EvaluationException
57
58
59struct DwarfExpressionEvaluator::EvaluationException {
60	const char* message;
61
62	EvaluationException(const char* message)
63		:
64		message(message)
65	{
66	}
67};
68
69
70// #pragma mark - DwarfExpressionEvaluator
71
72
73void
74DwarfExpressionEvaluator::_AssertMinStackSize(size_t size) const
75{
76	if (fStackSize < size)
77		throw EvaluationException("pop from empty stack");
78}
79
80
81void
82DwarfExpressionEvaluator::_Push(target_addr_t value)
83{
84	// resize the stack, if we hit the capacity
85	if (fStackSize == fStackCapacity) {
86		if (fStackCapacity >= kMaxStackCapacity)
87			throw EvaluationException("stack overflow");
88
89		size_t newCapacity = fStackCapacity + kStackCapacityIncrement;
90		target_addr_t* newStack = (target_addr_t*)realloc(fStack,
91			newCapacity * sizeof(target_addr_t));
92		if (newStack == NULL)
93			throw std::bad_alloc();
94
95		fStack = newStack;
96		fStackCapacity = newCapacity;
97	}
98
99	fStack[fStackSize++] = value;
100}
101
102
103target_addr_t
104DwarfExpressionEvaluator::_Pop()
105{
106	_AssertMinStackSize(1);
107	return fStack[--fStackSize];
108}
109
110
111DwarfExpressionEvaluator::DwarfExpressionEvaluator(
112	DwarfExpressionEvaluationContext* context)
113	:
114	fContext(context),
115	fStack(NULL),
116	fStackSize(0),
117	fStackCapacity(0)
118{
119}
120
121
122DwarfExpressionEvaluator::~DwarfExpressionEvaluator()
123{
124	free(fStack);
125}
126
127
128status_t
129DwarfExpressionEvaluator::Push(target_addr_t value)
130{
131	try {
132		_Push(value);
133		return B_OK;
134	} catch (const EvaluationException& exception) {
135		return B_BAD_VALUE;
136	} catch (const std::bad_alloc& exception) {
137		return B_NO_MEMORY;
138	}
139}
140
141
142status_t
143DwarfExpressionEvaluator::Evaluate(const void* expression, size_t size,
144	target_addr_t& _result)
145{
146	fDataReader.SetTo(expression, size, fContext->AddressSize(), fContext->IsBigEndian());
147
148	try {
149		status_t error = _Evaluate(NULL);
150		if (error != B_OK)
151			return error;
152		_result = _Pop();
153		return B_OK;
154	} catch (const EvaluationException& exception) {
155		WARNING("DwarfExpressionEvaluator::Evaluate(): %s\n",
156			exception.message);
157		return B_BAD_VALUE;
158	} catch (const std::bad_alloc& exception) {
159		return B_NO_MEMORY;
160	}
161}
162
163
164status_t
165DwarfExpressionEvaluator::EvaluateLocation(const void* expression, size_t size,
166	ValueLocation& _location)
167{
168	_location.Clear();
169
170	// the empty expression is a valid one
171	if (size == 0) {
172		ValuePieceLocation piece;
173		piece.SetToUnknown();
174		piece.SetSize(0);
175		return _location.AddPiece(piece) ? B_OK : B_NO_MEMORY;
176	}
177
178	fDataReader.SetTo(expression, size, fContext->AddressSize(), fContext->IsBigEndian());
179
180	// parse the first (and maybe only) expression
181	try {
182		// push the object address, if any
183		target_addr_t objectAddress;
184		if (fContext->GetObjectAddress(objectAddress))
185			_Push(objectAddress);
186
187		ValuePieceLocation piece;
188		status_t error = _Evaluate(&piece);
189		if (error != B_OK)
190			return error;
191
192		// if that's all, it's only a simple expression without composition
193		if (fDataReader.BytesRemaining() == 0) {
194			if (!piece.IsValid())
195				piece.SetToMemory(_Pop());
196			piece.SetSize(0);
197			return _location.AddPiece(piece) ? B_OK : B_NO_MEMORY;
198		}
199
200		// there's more, so it must be a composition operator
201		uint8 opcode = fDataReader.Read<uint8>(0);
202		if (opcode == DW_OP_piece) {
203			piece.SetSize(fDataReader.ReadUnsignedLEB128(0));
204		} else if (opcode == DW_OP_bit_piece) {
205			uint64 bitSize = fDataReader.ReadUnsignedLEB128(0);
206			piece.SetSize(bitSize, fDataReader.ReadUnsignedLEB128(0));
207		} else
208			return B_BAD_DATA;
209
210		// If there's a composition operator, there must be at least two
211		// simple expressions, so this must not be the end.
212		if (fDataReader.BytesRemaining() == 0)
213			return B_BAD_DATA;
214	} catch (const EvaluationException& exception) {
215		WARNING("DwarfExpressionEvaluator::EvaluateLocation(): %s\n",
216			exception.message);
217		return B_BAD_VALUE;
218	} catch (const std::bad_alloc& exception) {
219		return B_NO_MEMORY;
220	}
221
222	// parse subsequent expressions (at least one)
223	while (fDataReader.BytesRemaining() > 0) {
224		// Restrict the data reader to the remaining bytes to prevent jumping
225		// back.
226		fDataReader.SetTo(fDataReader.Data(), fDataReader.BytesRemaining(),
227			fDataReader.AddressSize(), fDataReader.IsBigEndian());
228
229		try {
230			// push the object address, if any
231			target_addr_t objectAddress;
232			if (fContext->GetObjectAddress(objectAddress))
233				_Push(objectAddress);
234
235			ValuePieceLocation piece;
236			status_t error = _Evaluate(&piece);
237			if (error != B_OK)
238				return error;
239
240			if (!piece.IsValid())
241				piece.SetToMemory(_Pop());
242
243			// each expression must be followed by a composition operator
244			if (fDataReader.BytesRemaining() == 0)
245				return B_BAD_DATA;
246
247			uint8 opcode = fDataReader.Read<uint8>(0);
248			if (opcode == DW_OP_piece) {
249				piece.SetSize(fDataReader.ReadUnsignedLEB128(0));
250			} else if (opcode == DW_OP_bit_piece) {
251				uint64 bitSize = fDataReader.ReadUnsignedLEB128(0);
252				piece.SetSize(bitSize, fDataReader.ReadUnsignedLEB128(0));
253			} else
254				return B_BAD_DATA;
255		} catch (const EvaluationException& exception) {
256			WARNING("DwarfExpressionEvaluator::EvaluateLocation(): %s\n",
257				exception.message);
258			return B_BAD_VALUE;
259		} catch (const std::bad_alloc& exception) {
260			return B_NO_MEMORY;
261		}
262	}
263
264	return B_OK;
265}
266
267
268status_t
269DwarfExpressionEvaluator::_Evaluate(ValuePieceLocation* _piece)
270{
271	TRACE_EXPR_ONLY({
272		TRACE_EXPR("DwarfExpressionEvaluator::_Evaluate(%p, %" B_PRIdOFF ")\n",
273			fDataReader.Data(), fDataReader.BytesRemaining());
274		const uint8* data = (const uint8*)fDataReader.Data();
275		int32 count = fDataReader.BytesRemaining();
276		for (int32 i = 0; i < count; i++)
277			TRACE_EXPR(" %02x", data[i]);
278		TRACE_EXPR("\n");
279	})
280
281	uint32 operationsExecuted = 0;
282
283	while (fDataReader.BytesRemaining() > 0) {
284		uint8 opcode = fDataReader.Read<uint8>(0);
285
286		switch (opcode) {
287			case DW_OP_addr:
288				TRACE_EXPR("  DW_OP_addr\n");
289				_Push(fDataReader.ReadAddress(0) + fContext->RelocationDelta());
290				break;
291			case DW_OP_const1u:
292				TRACE_EXPR("  DW_OP_const1u\n");
293				_Push(fDataReader.Read<uint8>(0));
294				break;
295			case DW_OP_const1s:
296				TRACE_EXPR("  DW_OP_const1s\n");
297				_Push(fDataReader.Read<int8>(0));
298				break;
299			case DW_OP_const2u:
300				TRACE_EXPR("  DW_OP_const2u\n");
301				_Push(fDataReader.Read<uint16>(0));
302				break;
303			case DW_OP_const2s:
304				TRACE_EXPR("  DW_OP_const2s\n");
305				_Push(fDataReader.Read<int16>(0));
306				break;
307			case DW_OP_const4u:
308				TRACE_EXPR("  DW_OP_const4u\n");
309				_Push(fDataReader.Read<uint32>(0));
310				break;
311			case DW_OP_const4s:
312				TRACE_EXPR("  DW_OP_const4s\n");
313				_Push(fDataReader.Read<int32>(0));
314				break;
315			case DW_OP_const8u:
316				TRACE_EXPR("  DW_OP_const8u\n");
317				_Push(fDataReader.Read<uint64>(0));
318				break;
319			case DW_OP_const8s:
320				TRACE_EXPR("  DW_OP_const8s\n");
321				_Push(fDataReader.Read<int64>(0));
322				break;
323			case DW_OP_constu:
324				TRACE_EXPR("  DW_OP_constu\n");
325				_Push(fDataReader.ReadUnsignedLEB128(0));
326				break;
327			case DW_OP_consts:
328				TRACE_EXPR("  DW_OP_consts\n");
329				_Push(fDataReader.ReadSignedLEB128(0));
330				break;
331			case DW_OP_dup:
332				TRACE_EXPR("  DW_OP_dup\n");
333				_AssertMinStackSize(1);
334				_Push(fStack[fStackSize - 1]);
335				break;
336			case DW_OP_drop:
337				TRACE_EXPR("  DW_OP_drop\n");
338				_Pop();
339				break;
340			case DW_OP_over:
341				TRACE_EXPR("  DW_OP_over\n");
342				_AssertMinStackSize(1);
343				_Push(fStack[fStackSize - 2]);
344				break;
345			case DW_OP_pick:
346			{
347				TRACE_EXPR("  DW_OP_pick\n");
348				uint8 index = fDataReader.Read<uint8>(0);
349				_AssertMinStackSize(index + 1);
350				_Push(fStack[fStackSize - index - 1]);
351				break;
352			}
353			case DW_OP_swap:
354			{
355				TRACE_EXPR("  DW_OP_swap\n");
356				_AssertMinStackSize(2);
357				std::swap(fStack[fStackSize - 1], fStack[fStackSize - 2]);
358				break;
359			}
360			case DW_OP_rot:
361			{
362				TRACE_EXPR("  DW_OP_rot\n");
363				_AssertMinStackSize(3);
364				target_addr_t tmp = fStack[fStackSize - 1];
365				fStack[fStackSize - 1] = fStack[fStackSize - 2];
366				fStack[fStackSize - 2] = fStack[fStackSize - 3];
367				fStack[fStackSize - 3] = tmp;
368				break;
369			}
370
371			case DW_OP_deref:
372				TRACE_EXPR("  DW_OP_deref\n");
373				_DereferenceAddress(fContext->AddressSize());
374				break;
375			case DW_OP_deref_size:
376				TRACE_EXPR("  DW_OP_deref_size\n");
377				_DereferenceAddress(fDataReader.Read<uint8>(0));
378				break;
379			case DW_OP_xderef:
380				TRACE_EXPR("  DW_OP_xderef\n");
381				_DereferenceAddressSpaceAddress(fContext->AddressSize());
382				break;
383			case DW_OP_xderef_size:
384				TRACE_EXPR("  DW_OP_xderef_size\n");
385				_DereferenceAddressSpaceAddress(fDataReader.Read<uint8>(0));
386				break;
387
388			case DW_OP_abs:
389			{
390				TRACE_EXPR("  DW_OP_abs\n");
391				target_addr_t value = _Pop();
392				if (fContext->AddressSize() == 4) {
393					int32 signedValue = (int32)value;
394					_Push(signedValue >= 0 ? signedValue : -signedValue);
395				} else {
396					int64 signedValue = (int64)value;
397					_Push(signedValue >= 0 ? signedValue : -signedValue);
398				}
399				break;
400			}
401			case DW_OP_and:
402				TRACE_EXPR("  DW_OP_and\n");
403				_Push(_Pop() & _Pop());
404				break;
405			case DW_OP_div:
406			{
407				TRACE_EXPR("  DW_OP_div\n");
408				int64 top = (int64)_Pop();
409				int64 second = (int64)_Pop();
410				_Push(top != 0 ? second / top : 0);
411				break;
412			}
413			case DW_OP_minus:
414			{
415				TRACE_EXPR("  DW_OP_minus\n");
416				target_addr_t top = _Pop();
417				_Push(_Pop() - top);
418				break;
419			}
420			case DW_OP_mod:
421			{
422				TRACE_EXPR("  DW_OP_mod\n");
423				// While the specs explicitly speak of signed integer division
424				// for "div", nothing is mentioned for "mod".
425				target_addr_t top = _Pop();
426				target_addr_t second = _Pop();
427				_Push(top != 0 ? second % top : 0);
428				break;
429			}
430			case DW_OP_mul:
431				TRACE_EXPR("  DW_OP_mul\n");
432				_Push(_Pop() * _Pop());
433				break;
434			case DW_OP_neg:
435			{
436				TRACE_EXPR("  DW_OP_neg\n");
437				if (fContext->AddressSize() == 4)
438					_Push(-(int32)_Pop());
439				else
440					_Push(-(int64)_Pop());
441				break;
442			}
443			case DW_OP_not:
444				TRACE_EXPR("  DW_OP_not\n");
445				_Push(~_Pop());
446				break;
447			case DW_OP_or:
448				TRACE_EXPR("  DW_OP_or\n");
449				_Push(_Pop() | _Pop());
450				break;
451			case DW_OP_plus:
452				TRACE_EXPR("  DW_OP_plus\n");
453				_Push(_Pop() + _Pop());
454				break;
455			case DW_OP_plus_uconst:
456				TRACE_EXPR("  DW_OP_plus_uconst\n");
457				_Push(_Pop() + fDataReader.ReadUnsignedLEB128(0));
458				break;
459			case DW_OP_shl:
460			{
461				TRACE_EXPR("  DW_OP_shl\n");
462				target_addr_t top = _Pop();
463				_Push(_Pop() << top);
464				break;
465			}
466			case DW_OP_shr:
467			{
468				TRACE_EXPR("  DW_OP_shr\n");
469				target_addr_t top = _Pop();
470				_Push(_Pop() >> top);
471				break;
472			}
473			case DW_OP_shra:
474			{
475				TRACE_EXPR("  DW_OP_shra\n");
476				target_addr_t top = _Pop();
477				int64 second = (int64)_Pop();
478				_Push(second >= 0 ? second >> top : -(-second >> top));
479					// right shift on negative values is implementation defined
480				break;
481			}
482			case DW_OP_xor:
483				TRACE_EXPR("  DW_OP_xor\n");
484				_Push(_Pop() ^ _Pop());
485				break;
486
487			case DW_OP_bra:
488				TRACE_EXPR("  DW_OP_bra\n");
489				if (_Pop() == 0)
490					break;
491				// fall through
492			case DW_OP_skip:
493			{
494				TRACE_EXPR("  DW_OP_skip\n");
495				int16 offset = fDataReader.Read<int16>(0);
496				if (offset >= 0 ? offset > fDataReader.BytesRemaining()
497						: -offset > fDataReader.Offset()) {
498					throw EvaluationException("bra/skip: invalid offset");
499				}
500				fDataReader.SeekAbsolute(fDataReader.Offset() + offset);
501				break;
502			}
503
504			case DW_OP_eq:
505				TRACE_EXPR("  DW_OP_eq\n");
506				_Push(_Pop() == _Pop() ? 1 : 0);
507				break;
508			case DW_OP_ge:
509			{
510				TRACE_EXPR("  DW_OP_ge\n");
511				int64 top = (int64)_Pop();
512				_Push((int64)_Pop() >= top ? 1 : 0);
513				break;
514			}
515			case DW_OP_gt:
516			{
517				TRACE_EXPR("  DW_OP_gt\n");
518				int64 top = (int64)_Pop();
519				_Push((int64)_Pop() > top ? 1 : 0);
520				break;
521			}
522			case DW_OP_le:
523			{
524				TRACE_EXPR("  DW_OP_le\n");
525				int64 top = (int64)_Pop();
526				_Push((int64)_Pop() <= top ? 1 : 0);
527				break;
528			}
529			case DW_OP_lt:
530			{
531				TRACE_EXPR("  DW_OP_lt\n");
532				int64 top = (int64)_Pop();
533				_Push((int64)_Pop() < top ? 1 : 0);
534				break;
535			}
536			case DW_OP_ne:
537				TRACE_EXPR("  DW_OP_ne\n");
538				_Push(_Pop() == _Pop() ? 1 : 0);
539				break;
540
541			case DW_OP_push_object_address:
542			{
543				TRACE_EXPR("  DW_OP_push_object_address\n");
544				target_addr_t address;
545				if (!fContext->GetObjectAddress(address))
546					throw EvaluationException("failed to get object address");
547				_Push(address);
548				break;
549			}
550			case DW_OP_call_frame_cfa:
551			{
552				TRACE_EXPR("  DW_OP_call_frame_cfa\n");
553				target_addr_t address;
554				if (!fContext->GetFrameAddress(address))
555					throw EvaluationException("failed to get frame address");
556				_Push(address);
557				break;
558			}
559			case DW_OP_fbreg:
560			{
561				int64 offset = fDataReader.ReadSignedLEB128(0);
562				TRACE_EXPR("  DW_OP_fbreg(%" B_PRId64 ")\n", offset);
563				target_addr_t address;
564				if (!fContext->GetFrameBaseAddress(address)) {
565					throw EvaluationException(
566						"failed to get frame base address");
567				}
568				_Push(address + offset);
569				break;
570			}
571			case DW_OP_form_tls_address:
572			{
573				TRACE_EXPR("  DW_OP_form_tls_address\n");
574				target_addr_t address;
575				if (!fContext->GetTLSAddress(_Pop(), address))
576					throw EvaluationException("failed to get tls address");
577				_Push(address);
578				break;
579			}
580
581			case DW_OP_regx:
582			{
583				TRACE_EXPR("  DW_OP_regx\n");
584				if (_piece == NULL) {
585					throw EvaluationException(
586						"DW_OP_regx in non-location expression");
587				}
588				uint32 reg = fDataReader.ReadUnsignedLEB128(0);
589				if (fDataReader.HasOverflow())
590					throw EvaluationException("unexpected end of expression");
591				_piece->SetToRegister(reg);
592				return B_OK;
593			}
594
595			case DW_OP_bregx:
596			{
597				TRACE_EXPR("  DW_OP_bregx\n");
598				uint32 reg = fDataReader.ReadUnsignedLEB128(0);
599				_PushRegister(reg, fDataReader.ReadSignedLEB128(0));
600				break;
601			}
602
603			case DW_OP_call2:
604				TRACE_EXPR("  DW_OP_call2\n");
605				_Call(fDataReader.Read<uint16>(0), dwarf_reference_type_local);
606				break;
607			case DW_OP_call4:
608				TRACE_EXPR("  DW_OP_call4\n");
609				_Call(fDataReader.Read<uint32>(0), dwarf_reference_type_local);
610				break;
611			case DW_OP_call_ref:
612				TRACE_EXPR("  DW_OP_call_ref\n");
613				if (fContext->AddressSize() == 4) {
614					_Call(fDataReader.Read<uint32>(0),
615						dwarf_reference_type_global);
616				} else {
617					_Call(fDataReader.Read<uint64>(0),
618						dwarf_reference_type_global);
619				}
620				break;
621
622			case DW_OP_piece:
623			case DW_OP_bit_piece:
624				// are handled in EvaluateLocation()
625				if (_piece == NULL)
626					return B_BAD_DATA;
627
628				fDataReader.SeekAbsolute(fDataReader.Offset() - 1);
629					// put back the operation
630				return B_OK;
631
632			case DW_OP_nop:
633				TRACE_EXPR("  DW_OP_nop\n");
634				break;
635
636			case DW_OP_implicit_value:
637			{
638				TRACE_EXPR("  DW_OP_implicit_value\n");
639				if (_piece == NULL) {
640					throw EvaluationException(
641						"DW_OP_implicit_value in non-location expression");
642				}
643				uint32 length = fDataReader.ReadUnsignedLEB128(0);
644				if (length == 0)
645					return B_BAD_DATA;
646
647				if (fDataReader.BytesRemaining() < length)
648					return B_BAD_DATA;
649
650				if (!_piece->SetToValue(fDataReader.Data(), length))
651					return B_NO_MEMORY;
652
653				return B_OK;
654			}
655			case DW_OP_stack_value:
656			{
657				TRACE_EXPR("  DW_OP_stack_value\n");
658				if (_piece == NULL) {
659					throw EvaluationException(
660						"DW_OP_stack_value in non-location expression");
661				}
662				if (fStackSize == 0)
663					return B_BAD_DATA;
664				target_addr_t value = _Pop();
665				if (!_piece->SetToValue(&value, sizeof(target_addr_t)))
666					return B_NO_MEMORY;
667
668				return B_OK;
669			}
670			default:
671				if (opcode >= DW_OP_lit0 && opcode <= DW_OP_lit31) {
672					TRACE_EXPR("  DW_OP_lit%u\n", opcode - DW_OP_lit0);
673					_Push(opcode - DW_OP_lit0);
674				} else if (opcode >= DW_OP_reg0 && opcode <= DW_OP_reg31) {
675					TRACE_EXPR("  DW_OP_reg%u\n", opcode - DW_OP_reg0);
676					if (_piece == NULL) {
677						// NOTE: Using these opcodes is actually only allowed in
678						// location expression, but gcc 2.95.3 does otherwise.
679						_PushRegister(opcode - DW_OP_reg0, 0);
680					} else {
681						_piece->SetToRegister(opcode - DW_OP_reg0);
682						return B_OK;
683					}
684				} else if (opcode >= DW_OP_breg0 && opcode <= DW_OP_breg31) {
685					int64 offset = fDataReader.ReadSignedLEB128(0);
686					TRACE_EXPR("  DW_OP_breg%u(%" B_PRId64 ")\n",
687						opcode - DW_OP_breg0, offset);
688					_PushRegister(opcode - DW_OP_breg0, offset);
689				} else {
690					WARNING("DwarfExpressionEvaluator::_Evaluate(): "
691						"unsupported opcode: %u\n", opcode);
692					return B_BAD_DATA;
693				}
694				break;
695		}
696
697		if (++operationsExecuted >= kMaxOperationCount)
698			return B_BAD_DATA;
699	}
700
701	return fDataReader.HasOverflow() ? B_BAD_DATA : B_OK;
702}
703
704
705void
706DwarfExpressionEvaluator::_DereferenceAddress(uint8 addressSize)
707{
708	uint32 valueType;
709	switch (addressSize) {
710		case 1:
711			valueType = B_UINT8_TYPE;
712			break;
713		case 2:
714			valueType = B_UINT16_TYPE;
715			break;
716		case 4:
717			valueType = B_UINT32_TYPE;
718			break;
719		case 8:
720			if (fContext->AddressSize() == 8) {
721				valueType = B_UINT64_TYPE;
722				break;
723			}
724			// fall through
725		default:
726			throw EvaluationException("invalid dereference size");
727	}
728
729	target_addr_t address = _Pop();
730	BVariant value;
731	if (!fContext->TargetInterface()->ReadValueFromMemory(address, valueType,
732			value)) {
733		throw EvaluationException("failed to read memory");
734	}
735
736	_Push(value.ToUInt64());
737}
738
739
740void
741DwarfExpressionEvaluator::_DereferenceAddressSpaceAddress(uint8 addressSize)
742{
743	uint32 valueType;
744	switch (addressSize) {
745		case 1:
746			valueType = B_UINT8_TYPE;
747			break;
748		case 2:
749			valueType = B_UINT16_TYPE;
750			break;
751		case 4:
752			valueType = B_UINT32_TYPE;
753			break;
754		case 8:
755			if (fContext->AddressSize() == 8) {
756				valueType = B_UINT64_TYPE;
757				break;
758			}
759			// fall through
760		default:
761			throw EvaluationException("invalid dereference size");
762	}
763
764	target_addr_t address = _Pop();
765	target_addr_t addressSpace = _Pop();
766	BVariant value;
767	if (!fContext->TargetInterface()->ReadValueFromMemory(addressSpace, address,
768			valueType, value)) {
769		throw EvaluationException("failed to read memory");
770	}
771
772	_Push(value.ToUInt64());
773}
774
775
776void
777DwarfExpressionEvaluator::_PushRegister(uint32 reg, target_addr_t offset)
778{
779	BVariant value;
780	if (!fContext->TargetInterface()->GetRegisterValue(reg, value))
781		throw EvaluationException("failed to get register");
782
783	_Push(value.ToUInt64() + offset);
784}
785
786
787void
788DwarfExpressionEvaluator::_Call(uint64 offset, uint8 refType)
789{
790	if (fDataReader.HasOverflow())
791		throw EvaluationException("unexpected end of expression");
792
793	// get the expression to "call"
794	const void* block;
795	off_t size;
796	if (fContext->GetCallTarget(offset, refType, block, size) != B_OK)
797		throw EvaluationException("failed to get call target");
798
799	// no expression is OK, then this is just a no-op
800	if (block == NULL)
801		return;
802
803	// save the current data reader state
804	DataReader savedReader = fDataReader;
805
806	// set the reader to the target expression
807	fDataReader.SetTo(block, size, savedReader.AddressSize(), savedReader.IsBigEndian());
808
809	// and evaluate it
810	try {
811		if (_Evaluate(NULL) != B_OK)
812			throw EvaluationException("call failed");
813	} catch (...) {
814		fDataReader = savedReader;
815		throw;
816	}
817
818	fDataReader = savedReader;
819}
820