162aa74f8SRafael Auler //===-- instr.cpp -----------------------------------------------*- C++ -*-===//
262aa74f8SRafael Auler //
362aa74f8SRafael Auler //                     The LLVM Compiler Infrastructure
462aa74f8SRafael Auler //
562aa74f8SRafael Auler // This file is distributed under the University of Illinois Open Source
662aa74f8SRafael Auler // License. See LICENSE.TXT for details.
762aa74f8SRafael Auler // This file contains code that is linked to the final binary with a function
862aa74f8SRafael Auler // that is called at program exit to dump instrumented data collected during
962aa74f8SRafael Auler // execution.
1062aa74f8SRafael Auler //
1162aa74f8SRafael Auler //===----------------------------------------------------------------------===//
1262aa74f8SRafael Auler //
13*821480d2SRafael Auler // BOLT runtime instrumentation library for x86 Linux.
1462aa74f8SRafael Auler //
1562aa74f8SRafael Auler //===----------------------------------------------------------------------===//
1662aa74f8SRafael Auler 
1762aa74f8SRafael Auler #include <cstdint>
18*821480d2SRafael Auler #include <elf.h>
1962aa74f8SRafael Auler 
2062aa74f8SRafael Auler // All extern declarations here need to be defined by BOLT itself.
2162aa74f8SRafael Auler 
2262aa74f8SRafael Auler // Counters inserted by instrumentation, incremented during runtime when
2362aa74f8SRafael Auler // points of interest (locations) in the program are reached.
2462aa74f8SRafael Auler extern uint64_t __bolt_instr_locations[];
2562aa74f8SRafael Auler // Number of counters.
2662aa74f8SRafael Auler extern uint32_t __bolt_instr_num_locs;
2762aa74f8SRafael Auler // Filename to dump data to.
2862aa74f8SRafael Auler extern char __bolt_instr_filename[];
2962aa74f8SRafael Auler 
3062aa74f8SRafael Auler // A location is a function name plus offset. Function name needs to be
3162aa74f8SRafael Auler // retrieved from the string table and is stored as an index to this table.
32*821480d2SRafael Auler struct Location {
3362aa74f8SRafael Auler   uint32_t FunctionName;
3462aa74f8SRafael Auler   uint32_t Offset;
35*821480d2SRafael Auler };
3662aa74f8SRafael Auler 
3762aa74f8SRafael Auler // An edge description defines an instrumented edge in the program, fully
3862aa74f8SRafael Auler // identified by where the jump is located and its destination.
39*821480d2SRafael Auler struct EdgeDescription {
4062aa74f8SRafael Auler   Location From;
4162aa74f8SRafael Auler   Location To;
42*821480d2SRafael Auler };
4362aa74f8SRafael Auler 
44*821480d2SRafael Auler // These need to be read from disk. They are generated by BOLT and written to
45*821480d2SRafael Auler // an ELF note section in the binary itself.
46*821480d2SRafael Auler struct InstrumentationInfo {
47*821480d2SRafael Auler   EdgeDescription *Descriptions;
48*821480d2SRafael Auler   char *Strings;    // String table with function names used in this binary
49*821480d2SRafael Auler   int FileDesc;     // File descriptor for the file on disk backing this
50*821480d2SRafael Auler                     // information in memory via mmap
51*821480d2SRafael Auler   uint8_t *MMapPtr; // The mmap ptr
52*821480d2SRafael Auler   int MMapSize;     // The mmap size
53*821480d2SRafael Auler };
5462aa74f8SRafael Auler 
5562aa74f8SRafael Auler // Declare some syscall wrappers we use throughout this code to avoid linking
5662aa74f8SRafael Auler // against system libc.
5762aa74f8SRafael Auler static uint64_t
58*821480d2SRafael Auler __open(const char *pathname,
5962aa74f8SRafael Auler        uint64_t flags,
6062aa74f8SRafael Auler        uint64_t mode) {
6162aa74f8SRafael Auler   uint64_t ret;
6262aa74f8SRafael Auler   __asm__ __volatile__ (
6362aa74f8SRafael Auler           "movq $2, %%rax\n"
6462aa74f8SRafael Auler           "syscall"
6562aa74f8SRafael Auler           : "=a"(ret)
6662aa74f8SRafael Auler           : "D"(pathname), "S"(flags), "d"(mode)
6762aa74f8SRafael Auler           : "cc", "rcx", "r11", "memory");
6862aa74f8SRafael Auler   return ret;
6962aa74f8SRafael Auler }
7062aa74f8SRafael Auler 
71*821480d2SRafael Auler static uint64_t __write(uint64_t fd, const void *buf, uint64_t count) {
7262aa74f8SRafael Auler   uint64_t ret;
7362aa74f8SRafael Auler   __asm__ __volatile__ (
7462aa74f8SRafael Auler           "movq $1, %%rax\n"
7562aa74f8SRafael Auler           "syscall\n"
7662aa74f8SRafael Auler           : "=a"(ret)
7762aa74f8SRafael Auler           : "D"(fd), "S"(buf), "d"(count)
7862aa74f8SRafael Auler           : "cc", "rcx", "r11", "memory");
7962aa74f8SRafael Auler   return ret;
8062aa74f8SRafael Auler }
8162aa74f8SRafael Auler 
82*821480d2SRafael Auler static uint64_t __lseek(uint64_t fd, uint64_t pos, uint64_t whence) {
83*821480d2SRafael Auler   uint64_t ret;
84*821480d2SRafael Auler   __asm__ __volatile__ (
85*821480d2SRafael Auler           "movq $8, %%rax\n"
86*821480d2SRafael Auler           "syscall\n"
87*821480d2SRafael Auler           : "=a"(ret)
88*821480d2SRafael Auler           : "D"(fd), "S"(pos), "d"(whence)
89*821480d2SRafael Auler           : "cc", "rcx", "r11", "memory");
90*821480d2SRafael Auler   return ret;
91*821480d2SRafael Auler }
92*821480d2SRafael Auler 
93*821480d2SRafael Auler static int __close(uint64_t fd) {
9462aa74f8SRafael Auler   uint64_t ret;
9562aa74f8SRafael Auler   __asm__ __volatile__ (
9662aa74f8SRafael Auler           "movq $3, %%rax\n"
9762aa74f8SRafael Auler           "syscall\n"
9862aa74f8SRafael Auler           : "=a"(ret)
9962aa74f8SRafael Auler           : "D"(fd)
10062aa74f8SRafael Auler           : "cc", "rcx", "r11", "memory");
10162aa74f8SRafael Auler   return ret;
10262aa74f8SRafael Auler }
10362aa74f8SRafael Auler 
104*821480d2SRafael Auler static void *__mmap(uint64_t addr, uint64_t size, uint64_t prot,
105*821480d2SRafael Auler                     uint64_t flags, uint64_t fd, uint64_t offset) {
106*821480d2SRafael Auler   void *ret;
107*821480d2SRafael Auler   register uint64_t r8 asm("r8") = fd;
108*821480d2SRafael Auler   register uint64_t r9 asm("r9") = offset;
109*821480d2SRafael Auler   register uint64_t r10 asm("r10") = flags;
110*821480d2SRafael Auler   __asm__ __volatile__ (
111*821480d2SRafael Auler           "movq $9, %%rax\n"
112*821480d2SRafael Auler           "syscall\n"
113*821480d2SRafael Auler           : "=a"(ret)
114*821480d2SRafael Auler           : "D"(addr), "S"(size), "d"(prot), "r"(r10), "r"(r8), "r"(r9)
115*821480d2SRafael Auler           : "cc", "rcx", "r11", "memory");
116*821480d2SRafael Auler   return ret;
117*821480d2SRafael Auler }
118*821480d2SRafael Auler 
119*821480d2SRafael Auler static uint64_t __munmap(void *addr, uint64_t size) {
120*821480d2SRafael Auler   uint64_t ret;
121*821480d2SRafael Auler   __asm__ __volatile__ (
122*821480d2SRafael Auler           "movq $11, %%rax\n"
123*821480d2SRafael Auler           "syscall\n"
124*821480d2SRafael Auler           : "=a"(ret)
125*821480d2SRafael Auler           : "D"(addr), "S"(size)
126*821480d2SRafael Auler           : "cc", "rcx", "r11", "memory");
127*821480d2SRafael Auler   return ret;
128*821480d2SRafael Auler }
129*821480d2SRafael Auler 
130*821480d2SRafael Auler static uint64_t __exit(uint64_t code) {
131*821480d2SRafael Auler   uint64_t ret;
132*821480d2SRafael Auler   __asm__ __volatile__ (
133*821480d2SRafael Auler           "movq $231, %%rax\n"
134*821480d2SRafael Auler           "syscall\n"
135*821480d2SRafael Auler           : "=a"(ret)
136*821480d2SRafael Auler           : "D"(code)
137*821480d2SRafael Auler           : "cc", "rcx", "r11", "memory");
138*821480d2SRafael Auler   return ret;
139*821480d2SRafael Auler }
140*821480d2SRafael Auler 
141*821480d2SRafael Auler // Helper functions for writing strings to the .fdata file
142*821480d2SRafael Auler 
143*821480d2SRafael Auler // Write number Num using Base to the buffer in OutBuf, returns a pointer to
144*821480d2SRafael Auler // the end of the string.
14562aa74f8SRafael Auler static char *intToStr(char *OutBuf, uint32_t Num, uint32_t Base) {
14662aa74f8SRafael Auler   const char *Chars = "0123456789abcdef";
14762aa74f8SRafael Auler   char Buf[20];
14862aa74f8SRafael Auler   char *Ptr = Buf;
14962aa74f8SRafael Auler   while (Num) {
15062aa74f8SRafael Auler     *Ptr++ = *(Chars + (Num % Base));
15162aa74f8SRafael Auler     Num /= Base;
15262aa74f8SRafael Auler   }
15362aa74f8SRafael Auler   if (Ptr == Buf) {
15462aa74f8SRafael Auler     *OutBuf++ = '0';
15562aa74f8SRafael Auler     return OutBuf;
15662aa74f8SRafael Auler   }
15762aa74f8SRafael Auler   while (Ptr != Buf) {
15862aa74f8SRafael Auler     *OutBuf++ = *--Ptr;
15962aa74f8SRafael Auler   }
16062aa74f8SRafael Auler   return OutBuf;
16162aa74f8SRafael Auler }
16262aa74f8SRafael Auler 
163*821480d2SRafael Auler // Copy Str to OutBuf, returns a pointer to the end of the copied string.
164*821480d2SRafael Auler static char *strCopy(char *OutBuf, const char *Str) {
165*821480d2SRafael Auler   while (*Str)
166*821480d2SRafael Auler     *OutBuf++ = *Str++;
167*821480d2SRafael Auler   return OutBuf;
168*821480d2SRafael Auler }
169*821480d2SRafael Auler 
170*821480d2SRafael Auler // Print Msg to STDERR and quits with error code 1.
171*821480d2SRafael Auler static void reportError(const char *Msg, uint64_t Size) {
172*821480d2SRafael Auler   __write(2, Msg, Size);
173*821480d2SRafael Auler   __exit(1);
174*821480d2SRafael Auler }
175*821480d2SRafael Auler 
176*821480d2SRafael Auler // Perform a string comparison and returns zero if Str1 matches Str2. Compares
177*821480d2SRafael Auler // at most Size characters.
178*821480d2SRafael Auler static int compareStr(const char *Str1, const char *Str2, int Size) {
179*821480d2SRafael Auler   while (*Str1 == *Str2) {
180*821480d2SRafael Auler     if (*Str1 == '\0' || --Size == 0)
181*821480d2SRafael Auler       return 0;
182*821480d2SRafael Auler     ++Str1;
183*821480d2SRafael Auler     ++Str2;
184*821480d2SRafael Auler   }
185*821480d2SRafael Auler   return 1;
186*821480d2SRafael Auler }
187*821480d2SRafael Auler 
188*821480d2SRafael Auler // Write as a string in OutBuf an identifier for the program point at function
189*821480d2SRafael Auler // whose name is in the string table index FuncStrIndex plus Offset.
190*821480d2SRafael Auler static char *serializeLoc(const InstrumentationInfo &Info, char *OutBuf,
191*821480d2SRafael Auler                           const Location Loc) {
192*821480d2SRafael Auler   // fdata location format: Type Name Offset
193*821480d2SRafael Auler   // Type 1 - regular symbol
194*821480d2SRafael Auler   OutBuf = strCopy(OutBuf, "1 ");
195*821480d2SRafael Auler   const char *Str = Info.Strings + Loc.FunctionName;
19662aa74f8SRafael Auler   while (*Str) {
19762aa74f8SRafael Auler     *OutBuf++ = *Str++;
19862aa74f8SRafael Auler   }
19962aa74f8SRafael Auler   *OutBuf++ = ' ';
200*821480d2SRafael Auler   OutBuf = intToStr(OutBuf, Loc.Offset, 16);
20162aa74f8SRafael Auler   *OutBuf++ = ' ';
20262aa74f8SRafael Auler   return OutBuf;
20362aa74f8SRafael Auler }
20462aa74f8SRafael Auler 
205*821480d2SRafael Auler // Read and map to memory the descriptions written by BOLT into the executable's
206*821480d2SRafael Auler // notes section
207*821480d2SRafael Auler static InstrumentationInfo readDescriptions() {
208*821480d2SRafael Auler   InstrumentationInfo Result;
209*821480d2SRafael Auler   uint64_t FD = __open("/proc/self/exe",
210*821480d2SRafael Auler                        /*flags=*/0 /*O_RDONLY*/,
211*821480d2SRafael Auler                        /*mode=*/0666);
212*821480d2SRafael Auler   Result.FileDesc = FD;
213*821480d2SRafael Auler 
214*821480d2SRafael Auler   // mmap our binary to memory
215*821480d2SRafael Auler   uint64_t Size = __lseek(FD, 0, 2 /*SEEK_END*/);
216*821480d2SRafael Auler   uint8_t *BinContents = reinterpret_cast<uint8_t *>(
217*821480d2SRafael Auler       __mmap(0, Size, 0x1 /* PROT_READ*/, 0x2 /* MAP_PRIVATE*/, FD, 0));
218*821480d2SRafael Auler   Result.MMapPtr = BinContents;
219*821480d2SRafael Auler   Result.MMapSize = Size;
220*821480d2SRafael Auler   Elf64_Ehdr *Hdr = reinterpret_cast<Elf64_Ehdr *>(BinContents);
221*821480d2SRafael Auler   Elf64_Shdr *Shdr = reinterpret_cast<Elf64_Shdr *>(BinContents + Hdr->e_shoff);
222*821480d2SRafael Auler   Elf64_Shdr *StringTblHeader = reinterpret_cast<Elf64_Shdr *>(
223*821480d2SRafael Auler       BinContents + Hdr->e_shoff + Hdr->e_shstrndx * Hdr->e_shentsize);
224*821480d2SRafael Auler 
225*821480d2SRafael Auler   // Find .bolt.instr.tables with the data we need and set pointers to it
226*821480d2SRafael Auler   for (int I = 0; I < Hdr->e_shnum; ++I) {
227*821480d2SRafael Auler     char *SecName = reinterpret_cast<char *>(
228*821480d2SRafael Auler         BinContents + StringTblHeader->sh_offset + Shdr->sh_name);
229*821480d2SRafael Auler     if (compareStr(SecName, ".bolt.instr.tables", 64) != 0) {
230*821480d2SRafael Auler       Shdr = reinterpret_cast<Elf64_Shdr *>(BinContents + Hdr->e_shoff +
231*821480d2SRafael Auler                                             (I + 1) * Hdr->e_shentsize);
232*821480d2SRafael Auler       continue;
233*821480d2SRafael Auler     }
234*821480d2SRafael Auler     // Actual contents of the ELF note start after offset 20 decimal:
235*821480d2SRafael Auler     //  Offset 0: Producer name size (4 bytes)
236*821480d2SRafael Auler     //  Offset 4: Contents size (4 bytes)
237*821480d2SRafael Auler     //  Offset 8: Note type (4 bytes)
238*821480d2SRafael Auler     //  Offset 12: Producer name (BOLT\0) (5 bytes + align to 4-byte boundary)
239*821480d2SRafael Auler     //  Offset 20: Contents
240*821480d2SRafael Auler     Result.Descriptions =
241*821480d2SRafael Auler         reinterpret_cast<EdgeDescription *>(BinContents + Shdr->sh_offset + 20);
242*821480d2SRafael Auler     // String table is located after the full EdgeDescriptions table containing
243*821480d2SRafael Auler     // __bolt_instr_num_locs entries is finished
244*821480d2SRafael Auler     Result.Strings = reinterpret_cast<char *>(
245*821480d2SRafael Auler         BinContents + Shdr->sh_offset + 20 +
246*821480d2SRafael Auler         (__bolt_instr_num_locs * sizeof(EdgeDescription)));
247*821480d2SRafael Auler     return Result;
248*821480d2SRafael Auler   }
249*821480d2SRafael Auler   const char ErrMsg[] =
250*821480d2SRafael Auler       "BOLT instrumentation runtime error: could not find section "
251*821480d2SRafael Auler       ".bolt.instr.tables\n";
252*821480d2SRafael Auler   reportError(ErrMsg, sizeof(ErrMsg));
253*821480d2SRafael Auler   return Result;
254*821480d2SRafael Auler }
255*821480d2SRafael Auler 
256*821480d2SRafael Auler // This is the entry point called at program exit. BOLT patches the executable's
257*821480d2SRafael Auler // FINI entry in the .dynamic section with the address of this function. Our
258*821480d2SRafael Auler // goal here is to flush to disk all instrumentation data in memory, using
259*821480d2SRafael Auler // BOLT's fdata format.
26062aa74f8SRafael Auler extern "C" void __bolt_instr_data_dump() {
261*821480d2SRafael Auler   const InstrumentationInfo Info = readDescriptions();
262*821480d2SRafael Auler 
263*821480d2SRafael Auler   uint64_t FD = __open(__bolt_instr_filename,
26462aa74f8SRafael Auler                        /*flags=*/0x241 /*O_WRONLY|O_TRUNC|O_CREAT*/,
26562aa74f8SRafael Auler                        /*mode=*/0666);
26662aa74f8SRafael Auler 
26762aa74f8SRafael Auler   for (int I = 0, E = __bolt_instr_num_locs; I < E; ++I) {
26862aa74f8SRafael Auler     char LineBuf[2000];
26962aa74f8SRafael Auler     char *Ptr = LineBuf;
27062aa74f8SRafael Auler     uint32_t HitCount = __bolt_instr_locations[I];
27162aa74f8SRafael Auler     if (!HitCount)
27262aa74f8SRafael Auler       continue;
27362aa74f8SRafael Auler 
274*821480d2SRafael Auler     EdgeDescription *Desc = &Info.Descriptions[I];
275*821480d2SRafael Auler     Ptr = serializeLoc(Info, Ptr, Desc->From);
276*821480d2SRafael Auler     Ptr = serializeLoc(Info, Ptr, Desc->To);
277*821480d2SRafael Auler     Ptr = strCopy(Ptr, "0 ");
27862aa74f8SRafael Auler     Ptr = intToStr(Ptr, HitCount, 10);
27962aa74f8SRafael Auler     *Ptr++ = '\n';
280*821480d2SRafael Auler     __write(FD, LineBuf, Ptr - LineBuf);
28162aa74f8SRafael Auler   }
282*821480d2SRafael Auler   __close(FD);
283*821480d2SRafael Auler   __munmap(Info.MMapPtr, Info.MMapSize);
284*821480d2SRafael Auler   __close(Info.FileDesc);
28562aa74f8SRafael Auler }
286