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