-
Notifications
You must be signed in to change notification settings - Fork 20
/
faults.go
117 lines (96 loc) · 3.21 KB
/
faults.go
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
107
108
109
110
111
112
113
114
115
116
117
// This file is part of Gopher2600.
//
// Gopher2600 is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Gopher2600 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Gopher2600. If not, see <https://www.gnu.org/licenses/>.
package faults
import (
"fmt"
"io"
)
// Category classifies the approximate reason for a memory fault
type Category string
// List of valid Category values
const (
NullDereference Category = "null dereference"
MisalignedAccess Category = "misaligned access"
StackCollision Category = "stack collision"
IllegalAddress Category = "illegal address"
UndefinedSymbol Category = "undefined symbol"
)
// Entry is a single entry in the fault log
type Entry struct {
Category Category
// description of the event that triggered the memory fault
Event string
// addresses related to the fault
InstructionAddr uint32
AccessAddr uint32
// number of times this specific illegal access has been seen
Count int
}
func (e Entry) String() string {
return fmt.Sprintf("%s: %s: %08x (PC: %08x)", e.Category, e.Event, e.AccessAddr, e.InstructionAddr)
}
// Faults records memory accesses by the coprocesser that are "illegal".
type Faults struct {
// entries are keyed by concatanation of InstructionAddr and AccessAddr expressed as a
// 16 character string
entries map[string]*Entry
// all the accesses in order of the first time they appear. the Count field
// in the IllegalAccessEntry can be used to see if that entry was seen more
// than once *after* the first appearance
Log []*Entry
// is true once a stack collision has been detected. once a stack collision
// has occured then subsequent illegal accesses cannot be trusted and will
// likely not be logged
HasStackCollision bool
}
func NewFaults() Faults {
return Faults{
entries: make(map[string]*Entry),
}
}
// Clear all entries from faults log. Does not clear the HasStackCollision flag
func (flt *Faults) Clear() {
clear(flt.entries)
flt.Log = flt.Log[:0]
}
// WriteLog writes the list of faults in the order they were added
func (flt Faults) WriteLog(w io.Writer) {
for _, e := range flt.Log {
w.Write([]byte(e.String()))
}
}
// NewEntry adds a new entry to the list of faults
func (flt *Faults) NewEntry(category Category, event string, instructionAddr uint32, accessAddr uint32) {
key := fmt.Sprintf("%08x%08x", instructionAddr, accessAddr)
e, found := flt.entries[key]
if !found {
e = &Entry{
Category: category,
Event: event,
InstructionAddr: instructionAddr,
AccessAddr: accessAddr,
}
// record entry
flt.entries[key] = e
// update log
flt.Log = append(flt.Log, e)
}
// increase the count for this entry
e.Count++
// if this is a stack collision then record that fact
if category == StackCollision {
flt.HasStackCollision = true
}
}