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