forked from mephi42/drtrace
-
Notifications
You must be signed in to change notification settings - Fork 0
/
trace_buffer.c
125 lines (108 loc) · 3.13 KB
/
trace_buffer.c
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
#include <inttypes.h>
#include <string.h>
#include "crc32.h"
#include "trace_buffer.h"
size_t tb_available(struct trace_buffer_t* tb) {
return tb_end(tb) - tb->current;
}
void* tb_end(struct trace_buffer_t* tb) {
return ((void*)tb) + tb->size;
}
void tb_flush(struct trace_buffer_t* tb) {
size_t size;
int64 pos;
size_t written;
void* aligned_current;
tb_tlv_complete(tb);
// Align current position to block boundary.
aligned_current = aligned_block(tb->current);
memset(tb->current, 'X', aligned_current - tb->current);
tb->current = aligned_current;
size = tb->current - (void*)&tb->block;
if(size == sizeof(struct block_t)) {
// Nothing to do.
return;
}
tb->block.length = (uint32_t)size;
tb->block.crc32 = 0;
tb->block.crc32 = crc32((char*)&tb->block, size);
// Write data.
dr_mutex_lock(tb->mutex);
pos = dr_file_tell(tb->file);
if(pos == -1) {
dr_fprintf(STDERR, "fatal: dr_file_tell() failed\n");
dr_exit_process(1);
}
dr_fprintf(STDERR,
"info: flushing tb=%p file-offset=%" PRId64 " size=%u"
" tb-thread=0x%" PRIx64 " current-thread=0x%" PRIx64 "\n",
tb,
pos,
(unsigned int)size,
tb->block.thread_id,
(uint64_t)dr_get_thread_id(dr_get_current_drcontext()));
written = dr_write_file(tb->file, &tb->block, size);
dr_mutex_unlock(tb->mutex);
if(written != size) {
dr_fprintf(STDERR, "fatal: dr_write_file() failed\n");
dr_exit_process(1);
}
// Reset position.
tb->current = tb + 1;
}
void tb_init(struct trace_buffer_t* tb,
size_t size,
file_t file,
void* mutex,
thread_id_t thread_id) {
tb->size = size;
tb->file = file;
tb->mutex = mutex;
tb->block.thread_id = (uint64_t)thread_id;
memset(&tb->block.reserved, 'X', sizeof(tb->block.reserved));
tb->current_tlv = NULL;
tb->current = tb + 1;
}
void tb_tlv(struct trace_buffer_t* tb, uint32_t type) {
void* original_current;
// Align current position.
original_current = tb->current;
tb->current = aligned_tlv(tb->current);
// Check if there is space for a new TLV.
if(tb_available(tb) < sizeof(struct tlv_t)) {
// Flush; assume resulting position is properly aligned.
tb_flush(tb);
} else {
// Fill padding.
memset(original_current, 'X', tb->current - original_current);
}
// Set up a new TLV.
tb->current_tlv = tb->current;
tb->current_tlv->type = type;
tb->current = tb->current_tlv + 1;
}
void tb_tlv_cancel(struct trace_buffer_t* tb) {
if(tb->current_tlv) {
tb->current = tb->current_tlv;
tb->current_tlv = NULL;
}
}
bool tb_tlv_is(struct trace_buffer_t* tb, uint32_t type) {
if(tb->current_tlv) {
return tb->current_tlv->type == type;
} else {
return false;
}
}
void tb_tlv_complete(struct trace_buffer_t* tb) {
if(tb->current_tlv) {
tb->current_tlv->length = tb->current - (void*)tb->current_tlv;
if(tb->current_tlv->type == TYPE_TRACE &&
tb->current_tlv->length == sizeof(struct tlv_t)) {
// Do not keep empty trace TLVs.
tb_tlv_cancel(tb);
} else {
tb->current_tlv = NULL;
}
}
}