-
Notifications
You must be signed in to change notification settings - Fork 0
/
trace_reader.cpp
153 lines (124 loc) · 4.31 KB
/
trace_reader.cpp
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include "device.h"
#include "fiasco/jdb_ktrace.h"
#include "fiasco/kip.h"
#include "fiasco/pcileechinfo.h"
#include "page_table.h"
#include "trace_reader.h"
#include <err.h>
#include <iostream>
#include <cassert>
TraceReader::TraceReader(std::string path)
{
/*
* Initialize screamer device.
*
* Algorithm:
* 0,1 windows only
* 2 old normal read
* 3 old tiny read
*
* Loglevel: heavy performance penalty if greater zero
*/
this->dev = new Device("FPGA://algo=2", 0x0);
/*
* Read info struct written by the JDB extension.
*/
if (!this->dev->kip->_res5[0])
errx(1, "no Pcileechinfo found");
printf("leech info %p\n", this->dev->kip->_res5[0]);
this->pi = new Pcileechinfo();
this->dev->read(this->dev->kip->_res5[0], sizeof(*this->pi), this->pi);
printf("status %p\n", pi->Tbuf_status_page);
printf("kdir %p\n", pi->kdir);
/*
* Validate read info struct and setup address resolution.
*/
if (!this->pi->Tbuf_status_page)
errx(1, "%s: no Tbuf_status_page found", __func__);
this->ptab = new PageTable(this->dev, pi->kdir);
this->dev->add_page_table(this->ptab);
/*
* Read Tracebuffer_status to get its address, size and the current position.
*/
struct Tracebuffer_status status = this->get_status();
this->tbuf_start = status.window[0].tracebuffer;
this->tbuf_end = status.window[1].tracebuffer + status.window[1].size;
this->tbuf_size = this->tbuf_end - this->tbuf_start;
this->last_read = this->tbuf_start;
this->last_read_num = 0;
this->last_write = this->last_read;
/*
* Initialize the internal buffer, the remote tracebuffer will be copied into.
*/
size_t n = this->tbuf_size / sizeof(l4_tracebuffer_entry_t);
this->buffer.resize(n);
/*
* Open output file.
*/
this->file.open(path, std::ios::out | std::ios::binary);
//std::cout << "tbuf_start: " << std::hex << tbuf_start << std::endl;
//std::cout << "tbuf_end: " << std::hex << tbuf_end << std::endl;
//std::cout << "tbuf_size: " << tbuf_size << std::endl;
//std::cout << "num: " << tbuf_size / sizeof(l4_tracebuffer_entry_t) << std::endl;
}
TraceReader::~TraceReader()
{
this->file.close();
delete this->ptab;
delete this->pi;
delete this->dev;
}
std::pair<size_t,size_t> TraceReader::get_new_records()
{
/* Need to call write_new_records() to not loose records */
assert(this->last_write == this->last_read);
std::pair<size_t,size_t> result(0,0);
struct Tracebuffer_status status = this->get_status();
/* No trace records available yet */
if (status.current == 0)
return result;
Address start = this->last_read;
Address end = this->last_read < status.current ? status.current : this->tbuf_end;
result.first = this->update_buffer(start, end);
/* Detect missed records */
uint64_t next_num = this->buffer[address_to_idx(start)]._number;
if (next_num != this->last_read_num + 1)
result.second = next_num - this->last_read_num;
this->last_read = end;
this->last_read_num = this->buffer[address_to_idx(end) - 1]._number;
return result;
}
void TraceReader::write_new_records() {
assert(this->last_write < this->last_read);
size_t last_idx = address_to_idx(this->last_write);
size_t current_idx = address_to_idx(this->last_read);
this->file.write((const char *) &this->buffer[last_idx], (current_idx-last_idx) * sizeof(l4_tracebuffer_entry_t));
/* Go back to buffer start */
if (this->last_read == this->tbuf_end)
this->last_read = this->tbuf_start;
this->last_write = this->last_read;
}
size_t TraceReader::update_buffer(Address start, Address end) {
assert(start < end);
/* align addresses */
Address start_aligned = start & pagemask;
Address end_aligned = end % pagesize == 0 ? end : (end & pagemask) + pagesize;
size_t idx = address_to_idx(start_aligned);
this->dev->read_virt(start_aligned, end_aligned-start_aligned, &this->buffer[idx]);
return (end - start) / sizeof(l4_tracebuffer_entry_t);
}
struct Tracebuffer_status TraceReader::get_status()
{
struct Tracebuffer_status status = { 0 };
this->dev->read(
this->ptab->virt_to_phys(this->pi->Tbuf_status_page),
sizeof(status),
&status
);
return status;
}
size_t TraceReader::address_to_idx(Address a) const {
assert(a >= this->tbuf_start);
assert(a <= this->tbuf_end);
return (a - this->tbuf_start) / sizeof(l4_tracebuffer_entry_t);
}