opagent.c

Go to the documentation of this file.
00001 
00028 /******************************************************************
00029  * ATTENTION: 
00030  *   When adding new functions to this interface, you MUST update
00031  *   opagent_symbols.ver.
00032  *
00033  *   If a change is made to an existing exported function, perform the
00034  *   the following steps.  As an example, assume op_open_agent()
00035  *   is being updated to include a 'dump_code' parameter. 
00036  *     1. Update the opagent.ver file with a new version node, and
00037  *        add the op_open_agent to it.  Note that op_open_agent
00038  *        is also still declared in the original version node.
00039  *     2. Add '__asm__(".symver <blah>") directives to this .c source file.
00040  *        For this example, the directives would be as follows:
00041  *            __asm__(".symver op_open_agent_1_0,op_open_agent@OPAGENT_1.0");
00042  *            __asm__(".symver op_open_agent_2_0,op_open_agent@@OPAGENT_2.0");
00043  *     3. Update the declaration of op_open_agent in the header file with
00044  *        the additional parameter.
00045  *     4. Change the name of the original op_open_agent to "op_open_agent_1_0"
00046  *        in this .c source file.
00047  *     5. Add the new op_open_agent_2_0(int dump_code) function in this
00048  *        .c source file.
00049  *            
00050  *   See libopagent/Makefile.am for more information.
00051  *******************************************************************/
00052 
00053 #include "config.h"
00054 #include <stdio.h>
00055 #include <errno.h>
00056 #include <string.h>
00057 #include <stdint.h>
00058 #include <limits.h>
00059 #include <sys/types.h>
00060 #include <sys/stat.h>
00061 #include <fcntl.h>
00062 #include <unistd.h>
00063 #include <time.h>
00064 #include <bfd.h>
00065 
00066 #include "opagent.h"
00067 #include "op_config.h"
00068 #include "jitdump.h"
00069 
00070 // Declare BFD-related global variables.
00071 static char * _bfd_target_name;
00072 static int _bfd_arch;
00073 static unsigned int _bfd_mach;
00074 
00075 // Define BFD-related global variables.
00076 static int define_bfd_vars(void)
00077 {
00078     bfd * bfd;
00079     bfd_boolean r;
00080     int len;
00081 #define MAX_PATHLENGTH 2048
00082     char mypath[MAX_PATHLENGTH];
00083      
00084     len = readlink("/proc/self/exe", mypath, sizeof(mypath));
00085      
00086     if (len < 0) {
00087         fprintf(stderr, "libopagent: readlink /proc/self/exe failed\n");
00088         return -1;
00089     }
00090     if (len >= MAX_PATHLENGTH) {
00091         fprintf(stderr, "libopagent: readlink /proc/self/exe returned"
00092             " path length longer than %d.\n", MAX_PATHLENGTH);
00093 
00094         return -1;
00095     }
00096     mypath[len] = '\0';
00097 
00098     bfd_init();
00099     bfd = bfd_openr(mypath, NULL);
00100     if (bfd == NULL) {
00101         bfd_perror("bfd_openr error. Cannot get required BFD info");
00102         return -1;
00103     }
00104     r = bfd_check_format(bfd, bfd_object);
00105     if (!r) {
00106         bfd_perror("bfd_get_arch error. Cannot get required BFD info");
00107         return -1;
00108     }
00109     _bfd_target_name =  bfd->xvec->name;
00110     _bfd_arch = bfd_get_arch(bfd);
00111     _bfd_mach = bfd_get_mach(bfd);
00112 
00113     return 0;
00114 }
00118 #define OP_MAJOR_VERSION 1
00119 #define OP_MINOR_VERSION 0
00120 
00121 #define AGENT_DIR OP_SESSION_DIR_DEFAULT "jitdump"
00122 
00123 #define MSG_MAXLEN 20
00124 
00125 op_agent_t op_open_agent(void)
00126 {
00127     char pad_bytes[7] = {0, 0, 0, 0, 0, 0, 0};
00128     int pad_cnt;
00129     char dump_path[PATH_MAX];
00130     char err_msg[PATH_MAX + 16];
00131     struct stat dirstat;
00132     int rc;
00133     struct jitheader header;
00134     int fd;
00135     struct timeval tv;
00136     FILE * dumpfile = NULL;
00137 
00138     rc = stat(AGENT_DIR, &dirstat);
00139     if (rc || !S_ISDIR(dirstat.st_mode)) {
00140         if (!rc)
00141             errno = ENOTDIR;
00142         fprintf(stderr,"libopagent: Jitdump agent directory %s "
00143             "missing\n", AGENT_DIR);
00144         fprintf(stderr,"libopagent: do opcontrol --setup or "
00145             "opcontrol --reset, first\n");
00146         return NULL;
00147     }
00148     snprintf(dump_path, PATH_MAX, "%s/%i.dump", AGENT_DIR, getpid());
00149     snprintf(err_msg, PATH_MAX + 16, "Error opening %s\n", dump_path);
00150     // make the dump file only accessible for the user for security reason.
00151     fd = creat(dump_path, S_IRUSR|S_IWUSR);
00152     if (fd == -1) {
00153         fprintf(stderr, "%s\n", err_msg);
00154         return NULL;
00155     }
00156     dumpfile = fdopen(fd, "w");
00157     if (!dumpfile) {
00158         fprintf(stderr, "%s\n", err_msg);
00159         return NULL;
00160     }
00161     if (define_bfd_vars())
00162         return NULL;
00163     header.magic = JITHEADER_MAGIC;
00164     header.version = JITHEADER_VERSION;
00165     header.totalsize = sizeof(header) + strlen(_bfd_target_name) + 1;
00166     /* calculate amount of padding '\0' */
00167     pad_cnt = PADDING_8ALIGNED(header.totalsize);
00168     header.totalsize += pad_cnt;
00169     header.bfd_arch = _bfd_arch;
00170     header.bfd_mach = _bfd_mach;
00171     if (gettimeofday(&tv, NULL)) {
00172         fprintf(stderr, "gettimeofday failed\n");
00173         return NULL;
00174     }
00175 
00176     header.timestamp = tv.tv_sec;
00177     snprintf(err_msg, PATH_MAX + 16, "Error writing to %s", dump_path);
00178     if (!fwrite(&header, sizeof(header), 1, dumpfile)) {
00179         fprintf(stderr, "%s\n", err_msg);
00180         return NULL;
00181     }
00182     if (!fwrite(_bfd_target_name, strlen(_bfd_target_name) + 1, 1,
00183             dumpfile)) {
00184         fprintf(stderr, "%s\n", err_msg);
00185         return NULL;
00186     }
00187     /* write padding '\0' if necessary */
00188     if (pad_cnt && !fwrite(pad_bytes, pad_cnt, 1, dumpfile)) {
00189         fprintf(stderr, "%s\n", err_msg);
00190         return NULL;
00191     }
00192     fflush(dumpfile);
00193     return (op_agent_t)dumpfile;
00194 }
00195 
00196 
00197 int op_close_agent(op_agent_t hdl)
00198 {
00199     struct jr_code_close rec;
00200     struct timeval tv;
00201     FILE * dumpfile = (FILE *) hdl;
00202     if (!dumpfile) {
00203         errno = EINVAL;
00204         return -1;
00205     }
00206     rec.id = JIT_CODE_CLOSE;
00207     rec.total_size = sizeof(rec);
00208     if (gettimeofday(&tv, NULL)) {
00209         fprintf(stderr, "gettimeofday failed\n");
00210         return -1;
00211     }
00212     rec.timestamp = tv.tv_sec;
00213 
00214     if (!fwrite(&rec, sizeof(rec), 1, dumpfile))
00215         return -1;
00216     fclose(dumpfile);
00217     dumpfile = NULL;
00218     return 0;
00219 }
00220 
00221 
00222 int op_write_native_code(op_agent_t hdl, char const * symbol_name,
00223     uint64_t vma, void const * code, unsigned int const size)
00224 {
00225     struct jr_code_load rec;
00226     struct timeval tv;
00227     size_t sz_symb_name;
00228     char pad_bytes[7] = { 0, 0, 0, 0, 0, 0, 0 };
00229     size_t padding_count;
00230     FILE * dumpfile = (FILE *) hdl;
00231 
00232     if (!dumpfile) {
00233         errno = EINVAL;
00234         fprintf(stderr, "Invalid hdl argument\n");
00235         return -1;
00236     }
00237     sz_symb_name = strlen(symbol_name) + 1;
00238 
00239     rec.id = JIT_CODE_LOAD;
00240     rec.code_size = size;
00241     rec.vma = vma;
00242     rec.code_addr = (u64) (uintptr_t) code;
00243     rec.total_size = code ? sizeof(rec) + sz_symb_name + size :
00244             sizeof(rec) + sz_symb_name;
00245     /* calculate amount of padding '\0' */
00246     padding_count = PADDING_8ALIGNED(rec.total_size);
00247     rec.total_size += padding_count;
00248     if (gettimeofday(&tv, NULL)) {
00249         fprintf(stderr, "gettimeofday failed\n");
00250         return -1;
00251     }
00252 
00253     rec.timestamp = tv.tv_sec;
00254 
00255     /* locking makes sure that we continuously write this record, if
00256      * we are called within a multi-threaded context */
00257     flockfile(dumpfile);
00258     /* Write record, symbol name, code (optionally), and (if necessary)
00259      * additonal padding \0 bytes.
00260      */
00261     if (fwrite_unlocked(&rec, sizeof(rec), 1, dumpfile) &&
00262         fwrite_unlocked(symbol_name, sz_symb_name, 1, dumpfile)) {
00263         if (code)
00264             fwrite_unlocked(code, size, 1, dumpfile);
00265         if (padding_count)
00266             fwrite_unlocked(pad_bytes, padding_count, 1, dumpfile);
00267         /* Always flush to ensure conversion code to elf will see
00268          * data as soon as possible */
00269         fflush_unlocked(dumpfile);
00270         funlockfile(dumpfile);
00271         return 0;
00272     }
00273     fflush_unlocked(dumpfile);
00274     funlockfile(dumpfile);
00275     return -1;
00276 }
00277 
00278 
00279 int op_write_debug_line_info(op_agent_t hdl, void const * code,
00280                  size_t nr_entry,
00281                  struct debug_line_info const * compile_map)
00282 {
00283     struct jr_code_debug_info rec;
00284     long cur_pos, last_pos;
00285     struct timeval tv;
00286     size_t i;
00287     size_t padding_count;
00288     char padd_bytes[7] = {0, 0, 0, 0, 0, 0, 0};
00289     int rc = -1;
00290     FILE * dumpfile = (FILE *) hdl;
00291 
00292     if (!dumpfile) {
00293         errno = EINVAL;
00294         fprintf(stderr, "Invalid hdl argument\n");
00295         return -1;
00296     }
00297     
00298     /* write nothing if no entries are provided */
00299     if (nr_entry == 0)
00300         return 0;
00301 
00302     rec.id = JIT_CODE_DEBUG_INFO;
00303     rec.code_addr = (uint64_t)(uintptr_t)code;
00304     /* will be fixed after writing debug line info */
00305     rec.total_size = 0;
00306     rec.nr_entry = nr_entry;
00307     if (gettimeofday(&tv, NULL)) {
00308         fprintf(stderr, "gettimeofday failed\n");
00309         return -1;
00310     }
00311 
00312     rec.timestamp = tv.tv_sec;
00313 
00314     flockfile(dumpfile);
00315 
00316     if ((cur_pos = ftell(dumpfile)) == -1l)
00317         goto error;
00318     if (!fwrite_unlocked(&rec, sizeof(rec), 1, dumpfile))
00319         goto error;
00320     for (i = 0; i < nr_entry; ++i) {
00321         if (!fwrite_unlocked(&compile_map[i].vma,
00322                      sizeof(compile_map[i].vma), 1,
00323                      dumpfile) ||
00324             !fwrite_unlocked(&compile_map[i].lineno,
00325                      sizeof(compile_map[i].lineno), 1,
00326                      dumpfile) ||
00327             !fwrite_unlocked(compile_map[i].filename,
00328                      strlen(compile_map[i].filename) + 1, 1,
00329                      dumpfile))
00330             goto error;
00331     }
00332 
00333     if ((last_pos = ftell(dumpfile)) == -1l)
00334         goto error;
00335     rec.total_size = last_pos - cur_pos;
00336     padding_count = PADDING_8ALIGNED(rec.total_size);
00337     rec.total_size += padding_count;
00338     if (padding_count && !fwrite(padd_bytes, padding_count, 1, dumpfile))
00339         goto error;
00340     if (fseek(dumpfile, cur_pos, SEEK_SET) == -1l)
00341         goto error;
00342     if (!fwrite_unlocked(&rec, sizeof(rec), 1, dumpfile))
00343         goto error;
00344     if (fseek(dumpfile, last_pos + padding_count, SEEK_SET) == -1)
00345         goto error;
00346 
00347     rc = 0;
00348 error:
00349     fflush_unlocked(dumpfile);
00350     funlockfile(dumpfile);
00351     return rc;
00352 }
00353 
00354 
00355 int op_unload_native_code(op_agent_t hdl, uint64_t vma)
00356 {
00357     struct jr_code_unload rec;
00358     struct timeval tv;
00359     FILE * dumpfile = (FILE *) hdl;
00360 
00361     if (!dumpfile) {
00362         errno = EINVAL;
00363         fprintf(stderr, "Invalid hdl argument\n");
00364         return -1;
00365     }
00366 
00367     rec.id = JIT_CODE_UNLOAD;
00368     rec.vma = vma;
00369     rec.total_size = sizeof(rec);
00370     if (gettimeofday(&tv, NULL)) {
00371         fprintf(stderr, "gettimeofday failed\n");
00372         return -1;
00373     }
00374     rec.timestamp = tv.tv_sec;
00375 
00376     if (!fwrite(&rec, sizeof(rec), 1, dumpfile))
00377         return -1;
00378     fflush(dumpfile);
00379     return 0;
00380 }
00381 
00382 int op_major_version(void)
00383 {
00384     return OP_MAJOR_VERSION;
00385 }
00386 
00387 int op_minor_version(void)
00388 {
00389     return OP_MINOR_VERSION;
00390 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1