-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpath_logging.c
133 lines (104 loc) · 2.67 KB
/
path_logging.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
126
127
128
129
130
131
132
133
/* -*- Mode: C; tab-width: 8; c-basic-offset: 8; indent-tabs-mode: t; -*- */
//#define DEBUGTAG "PathLogging"
#include <assert.h>
#include <inttypes.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <syscall.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <rr/rr.h>
#define PAGE_SIZE 4096
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define PAGE_ALIGN(x) ((x + PAGE_SIZE - 1) & PAGE_MASK)
#define PATH_RECORD_BUFFER_SIZE (1 << 5)
#ifdef DEBUGTAG
# define DEBUG(msg, ...) \
fprintf(stderr, "[" DEBUGTAG "][%ld] " msg "\n", \
syscall(SYS_gettid), ## __VA_ARGS__)
#else
# define DEBUG(msg, ...)
#endif
struct path_record {
void* fn;
int32_t path;
};
struct path_records {
struct path_record recs[PATH_RECORD_BUFFER_SIZE];
ssize_t len : 30;
ssize_t finished : 1;
};
static pthread_once_t init_process_once = PTHREAD_ONCE_INIT;
static pthread_key_t finish_buffer_key;
static __thread struct path_records* record_buffer;
static int sys_write(int fd, void* buf, size_t len)
{
return syscall(SYS_write, fd, buf, len);
}
static void flush_buffer(struct path_records* buf)
{
DEBUG("Flushing buffer");
sys_write(RR_MAGIC_SAVE_DATA_FD, &buf->recs,
buf->len * sizeof(buf->recs[0]));
buf->len = 0;
}
static void drop_buffer(void)
{
struct path_records* buf = record_buffer;
pthread_setspecific(finish_buffer_key, NULL);
record_buffer = NULL;
munmap(buf, PAGE_ALIGN(sizeof(*buf)));
}
static void finish_buffer(void* pbuf)
{
struct path_records* buf = pbuf;
DEBUG("Finishing buffer");
flush_buffer(buf);
drop_buffer();
}
static void finish_main_thread_buffer_hack(void)
{
struct path_records* buf = record_buffer;
if (buf) {
finish_buffer(buf);
}
}
static void init_process(void)
{
pthread_atfork(NULL, NULL, drop_buffer);
pthread_key_create(&finish_buffer_key, finish_buffer);
atexit(finish_main_thread_buffer_hack);
}
static struct path_records* ensure_thread_init(void)
{
struct path_records* buf = record_buffer;
if (buf) {
return buf;
}
DEBUG("Initializing buffer");
pthread_once(&init_process_once, init_process);
buf = mmap(NULL, PAGE_ALIGN(sizeof(*buf)),
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
record_buffer = buf;
pthread_setspecific(finish_buffer_key, buf);
return buf;
}
void llvm_increment_path_count(int8_t* fn, int32_t path)
{
struct path_records* buf = ensure_thread_init();
struct path_record* rec = &buf->recs[buf->len++];
rec->fn = fn;
rec->path = path;
DEBUG("Retired (%p, %d)", rec->fn, rec->path);
if (PATH_RECORD_BUFFER_SIZE == buf->len) {
flush_buffer(buf);
}
}
void llvm_decrement_path_count (int8_t* fn, int32_t path)
{
/* ignored */
}