File: StackTrace.h

package info (click to toggle)
storm-lang 0.7.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 52,004 kB
  • sloc: ansic: 261,462; cpp: 140,405; sh: 14,891; perl: 9,846; python: 2,525; lisp: 2,504; asm: 860; makefile: 678; pascal: 70; java: 52; xml: 37; awk: 12
file content (106 lines) | stat: -rw-r--r-- 3,067 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#pragma once

/**
 * Collection of a stack trace, and tools for showing it to the user using the information
 * available in the Arena for symbolic lookup, alongside any debug information for the C++ code.
 * This will be extended to allow for inspection later on, so that the one who generated code
 * can inspect variables and similar things.
 */

/**
 * Fixed-size data entry for stack traces.
 */
struct StackFrame {
	StackFrame() : fnBase(null), offset(0), id(0), returnLocation(0) {}

	// Base and offset for the function.
	void *fnBase;
	int offset;

	// Get the function as a full pointer.
	inline void *fn() const {
		return (byte *)fnBase + offset;
	}

	// Which backend produced the data above.
	int id;

	// Location of the return adress on the stack for this frame. I.e. where is the address that
	// *returns to* this frame stored in memory? Might be null.
	void *returnLocation;

	// Update the return location if it is non-null. On some architectures (e.g. ARM64) this
	// function might need to sign the pointer as required by the ABI spec.
	void updateReturnLocation(const void *target) const;
};


/**
 * Representation of the stack trace itself. It will collect a copy of the stack with minimal processing
 * so that we can later inspect the data when and if we want to. However, this means that any data stored
 * here should not be considered live objects, since they are nothing more than a bitwise copy of the
 * original value.
 * This is since we probably want to include a Trace in exceptions, and we want to do as little as possible
 * when an exception is thrown in order to minimize code that should not fail. Also, we do not want to spend
 * time generating things that will never be shown anyway.
 */
class StackTrace : public Printable {
public:

	// Create an empty stack trace.
	StackTrace();

	// Create a trace with 'n' uninitialized frames in it.
	StackTrace(nat n);

	// Dtor.
	~StackTrace();

	// Copy.
	StackTrace(const StackTrace &o);
	StackTrace &operator =(const StackTrace &o);

	// Element access.
	inline StackFrame &operator [] (nat i) { return frames[i]; }
	inline const StackFrame &operator [] (nat i) const { return frames[i]; }

	// Size.
	inline nat count() const { return size; }

	// Add an element (grows).
	void push(const StackFrame &frame);

protected:
	// Output. Not formatted in any way.
	virtual void output(wostream &to) const;

private:
	// Storage of the data.
	StackFrame *frames;

	// Number of frames.
	nat size;

	// Capacity.
	nat capacity;
};

// Generate a stack trace from the calling point in the code.
StackTrace stackTrace(nat skip = 0);

// Fromat an entire trace.
String format(const StackTrace &trace);


// Generate a stack trace using a custom container.
class TraceGen {
public:
	// Initialize the data structure with 'count' elements.
	virtual void init(size_t count) = 0;

	// Add a frame.
	virtual void put(const StackFrame &frame) = 0;
};

// State is a pointer to a platform-specific collected stack state.
void createStackTrace(TraceGen &gen, nat skip = 0, void *state = null);