1*62aa74f8SRafael Auler //===-- instr.cpp -----------------------------------------------*- C++ -*-===//
2*62aa74f8SRafael Auler //
3*62aa74f8SRafael Auler //                     The LLVM Compiler Infrastructure
4*62aa74f8SRafael Auler //
5*62aa74f8SRafael Auler // This file is distributed under the University of Illinois Open Source
6*62aa74f8SRafael Auler // License. See LICENSE.TXT for details.
7*62aa74f8SRafael Auler // This file contains code that is linked to the final binary with a function
8*62aa74f8SRafael Auler // that is called at program exit to dump instrumented data collected during
9*62aa74f8SRafael Auler // execution.
10*62aa74f8SRafael Auler //
11*62aa74f8SRafael Auler //===----------------------------------------------------------------------===//
12*62aa74f8SRafael Auler //
13*62aa74f8SRafael Auler // BOLT runtime instrumentation library.
14*62aa74f8SRafael Auler //
15*62aa74f8SRafael Auler //===----------------------------------------------------------------------===//
16*62aa74f8SRafael Auler 
17*62aa74f8SRafael Auler #include <cstdint>
18*62aa74f8SRafael Auler 
19*62aa74f8SRafael Auler // All extern declarations here need to be defined by BOLT itself.
20*62aa74f8SRafael Auler 
21*62aa74f8SRafael Auler // Counters inserted by instrumentation, incremented during runtime when
22*62aa74f8SRafael Auler // points of interest (locations) in the program are reached.
23*62aa74f8SRafael Auler extern uint64_t __bolt_instr_locations[];
24*62aa74f8SRafael Auler // Number of counters.
25*62aa74f8SRafael Auler extern uint32_t __bolt_instr_num_locs;
26*62aa74f8SRafael Auler // String table with function names.
27*62aa74f8SRafael Auler extern char __bolt_instr_strings[];
28*62aa74f8SRafael Auler // Filename to dump data to.
29*62aa74f8SRafael Auler extern char __bolt_instr_filename[];
30*62aa74f8SRafael Auler 
31*62aa74f8SRafael Auler // A location is a function name plus offset. Function name needs to be
32*62aa74f8SRafael Auler // retrieved from the string table and is stored as an index to this table.
33*62aa74f8SRafael Auler typedef struct _Location {
34*62aa74f8SRafael Auler   uint32_t FunctionName;
35*62aa74f8SRafael Auler   uint32_t Offset;
36*62aa74f8SRafael Auler } Location;
37*62aa74f8SRafael Auler 
38*62aa74f8SRafael Auler // An edge description defines an instrumented edge in the program, fully
39*62aa74f8SRafael Auler // identified by where the jump is located and its destination.
40*62aa74f8SRafael Auler typedef struct _EdgeDescription {
41*62aa74f8SRafael Auler   Location From;
42*62aa74f8SRafael Auler   Location To;
43*62aa74f8SRafael Auler } EdgeDescription;
44*62aa74f8SRafael Auler 
45*62aa74f8SRafael Auler extern EdgeDescription __bolt_instr_descriptions[];
46*62aa74f8SRafael Auler 
47*62aa74f8SRafael Auler // Declare some syscall wrappers we use throughout this code to avoid linking
48*62aa74f8SRafael Auler // against system libc.
49*62aa74f8SRafael Auler static uint64_t
50*62aa74f8SRafael Auler myopen(const char *pathname,
51*62aa74f8SRafael Auler        uint64_t flags,
52*62aa74f8SRafael Auler        uint64_t mode) {
53*62aa74f8SRafael Auler   uint64_t ret;
54*62aa74f8SRafael Auler   __asm__ __volatile__ (
55*62aa74f8SRafael Auler           "movq $2, %%rax\n"
56*62aa74f8SRafael Auler           "syscall"
57*62aa74f8SRafael Auler           : "=a"(ret)
58*62aa74f8SRafael Auler           : "D"(pathname), "S"(flags), "d"(mode)
59*62aa74f8SRafael Auler           : "cc", "rcx", "r11", "memory");
60*62aa74f8SRafael Auler   return ret;
61*62aa74f8SRafael Auler }
62*62aa74f8SRafael Auler 
63*62aa74f8SRafael Auler static uint64_t mywrite(uint64_t fd, const void *buf, uint64_t count) {
64*62aa74f8SRafael Auler   uint64_t ret;
65*62aa74f8SRafael Auler   __asm__ __volatile__ (
66*62aa74f8SRafael Auler           "movq $1, %%rax\n"
67*62aa74f8SRafael Auler           "syscall\n"
68*62aa74f8SRafael Auler           : "=a"(ret)
69*62aa74f8SRafael Auler           : "D"(fd), "S"(buf), "d"(count)
70*62aa74f8SRafael Auler           : "cc", "rcx", "r11", "memory");
71*62aa74f8SRafael Auler   return ret;
72*62aa74f8SRafael Auler }
73*62aa74f8SRafael Auler 
74*62aa74f8SRafael Auler static int myclose(uint64_t fd) {
75*62aa74f8SRafael Auler   uint64_t ret;
76*62aa74f8SRafael Auler   __asm__ __volatile__ (
77*62aa74f8SRafael Auler           "movq $3, %%rax\n"
78*62aa74f8SRafael Auler           "syscall\n"
79*62aa74f8SRafael Auler           : "=a"(ret)
80*62aa74f8SRafael Auler           : "D"(fd)
81*62aa74f8SRafael Auler           : "cc", "rcx", "r11", "memory");
82*62aa74f8SRafael Auler   return ret;
83*62aa74f8SRafael Auler }
84*62aa74f8SRafael Auler 
85*62aa74f8SRafael Auler static char *intToStr(char *OutBuf, uint32_t Num, uint32_t Base) {
86*62aa74f8SRafael Auler   const char *Chars = "0123456789abcdef";
87*62aa74f8SRafael Auler   char Buf[20];
88*62aa74f8SRafael Auler   char *Ptr = Buf;
89*62aa74f8SRafael Auler   while (Num) {
90*62aa74f8SRafael Auler     *Ptr++ = *(Chars + (Num % Base));
91*62aa74f8SRafael Auler     Num /= Base;
92*62aa74f8SRafael Auler   }
93*62aa74f8SRafael Auler   if (Ptr == Buf) {
94*62aa74f8SRafael Auler     *OutBuf++ = '0';
95*62aa74f8SRafael Auler     return OutBuf;
96*62aa74f8SRafael Auler   }
97*62aa74f8SRafael Auler   while (Ptr != Buf) {
98*62aa74f8SRafael Auler     *OutBuf++ = *--Ptr;
99*62aa74f8SRafael Auler   }
100*62aa74f8SRafael Auler   return OutBuf;
101*62aa74f8SRafael Auler }
102*62aa74f8SRafael Auler 
103*62aa74f8SRafael Auler static char *serializeLoc(char *OutBuf, uint32_t FuncStrIndex,
104*62aa74f8SRafael Auler                           uint32_t Offset) {
105*62aa74f8SRafael Auler   *OutBuf++ = '1';
106*62aa74f8SRafael Auler   *OutBuf++ = ' ';
107*62aa74f8SRafael Auler   char *Str = __bolt_instr_strings + FuncStrIndex;
108*62aa74f8SRafael Auler   while (*Str) {
109*62aa74f8SRafael Auler     *OutBuf++ = *Str++;
110*62aa74f8SRafael Auler   }
111*62aa74f8SRafael Auler   *OutBuf++ = ' ';
112*62aa74f8SRafael Auler   OutBuf = intToStr(OutBuf, Offset, 16);
113*62aa74f8SRafael Auler   *OutBuf++ = ' ';
114*62aa74f8SRafael Auler   return OutBuf;
115*62aa74f8SRafael Auler }
116*62aa74f8SRafael Auler 
117*62aa74f8SRafael Auler extern "C" void __bolt_instr_data_dump() {
118*62aa74f8SRafael Auler   uint64_t FD = myopen(__bolt_instr_filename,
119*62aa74f8SRafael Auler                        /*flags=*/0x241 /*O_WRONLY|O_TRUNC|O_CREAT*/,
120*62aa74f8SRafael Auler                        /*mode=*/0666);
121*62aa74f8SRafael Auler 
122*62aa74f8SRafael Auler   for (int I = 0, E = __bolt_instr_num_locs; I < E; ++I) {
123*62aa74f8SRafael Auler     char LineBuf[2000];
124*62aa74f8SRafael Auler     char *Ptr = LineBuf;
125*62aa74f8SRafael Auler     uint32_t HitCount = __bolt_instr_locations[I];
126*62aa74f8SRafael Auler     if (!HitCount)
127*62aa74f8SRafael Auler       continue;
128*62aa74f8SRafael Auler 
129*62aa74f8SRafael Auler     EdgeDescription *Desc = &__bolt_instr_descriptions[I];
130*62aa74f8SRafael Auler     Ptr = serializeLoc(Ptr, Desc->From.FunctionName, Desc->From.Offset);
131*62aa74f8SRafael Auler     Ptr = serializeLoc(Ptr, Desc->To.FunctionName, Desc->To.Offset);
132*62aa74f8SRafael Auler     *Ptr++ = '0';
133*62aa74f8SRafael Auler     *Ptr++ = ' ';
134*62aa74f8SRafael Auler     Ptr = intToStr(Ptr, HitCount, 10);
135*62aa74f8SRafael Auler     *Ptr++ = '\n';
136*62aa74f8SRafael Auler     mywrite(FD, LineBuf, Ptr - LineBuf);
137*62aa74f8SRafael Auler   }
138*62aa74f8SRafael Auler   myclose(FD);
139*62aa74f8SRafael Auler }
140