Defined a symbol that I forget to define, stache_blk_size
[dyninst.git] / rtinst / src / RTposix.c
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 /************************************************************************
43  * RTposix.c: runtime instrumentation functions for generic posix.
44  *
45  * RTposix.c,v
46  * Revision 1.10  1995/05/18  11:08:27  markc
47  * added guard prevent timer start-stop during alarm handler
48  * added version number
49  *
50  * Revision 1.9  1995/03/10  19:39:42  hollings
51  * Fixed an ugly race condition in observed cost.
52  *
53  * Added the use of unix profil to compute the time spent in inst code.
54  *
55  *
56  ************************************************************************/
57
58 #ifdef SHM_SAMPLING
59 #include <sys/types.h>
60 #include <sys/ipc.h>
61 #include <sys/shm.h>
62 #endif
63
64 #include <assert.h>
65 #include <errno.h>
66 #include <fcntl.h>
67 #include <memory.h>
68 #include <signal.h>
69 #include <stdio.h>
70 #include <stdlib.h>
71 #include <string.h>
72 #include <sys/time.h>
73 #include <sys/uio.h>
74 #include <sys/socket.h>
75 #include <unistd.h>
76
77 #ifdef rs6000_ibm_aix4_1
78 #else
79 #include <sys/syscall.h>
80 #endif
81
82 #include <math.h>
83
84 #include "kludges.h"
85 #include "rtinst/h/rtinst.h"
86 #include "rtinst/h/trace.h"
87 #include "util/h/sys.h"
88
89
90 /* sunos's header files don't have these: */
91 #ifdef sparc_sun_sunos4_1_3
92 extern int socket(int, int, int);
93 extern int connect(int, struct sockaddr *, int);
94 extern int fwrite(void *, int, int, FILE *);
95 extern int setvbuf(FILE *, char *, int, int);
96 #ifdef SHM_SAMPLING
97 extern int shmget(key_t, unsigned, unsigned);
98 extern void *shmat(int, void *, int);
99 extern int shmdt(void*);
100 extern int shmctl(int, int, struct shmid_ds *);
101 #endif
102 #endif
103
104
105
106 /************************************************************************
107  * void DYNINSTbreakPoint(void)
108  *
109  * stop oneself.
110 ************************************************************************/
111
112 void
113 DYNINSTbreakPoint(void) {
114     kill(getpid(), SIGSTOP);
115 }
116
117
118
119 /************************************************************************
120  * void DYNINST_install_ualarm_interval(unsigned interval)
121  *
122  * an implementation of "ualarm" using the "setitimer" syscall.
123  * interval is in microseconds
124 ************************************************************************/
125
126 #if !defined(hppa1_1_hp_hpux)
127 extern void DYNINSTalarmExpire(int signo);
128 #else 
129 extern void DYNINSTalarmExpire(int signo, int code, struct sigcontext *scp);
130 #endif
131
132 #ifndef SHM_SAMPLING
133 void
134 DYNINST_install_ualarm(unsigned interval) {
135     struct itimerval it;
136     struct sigaction act;
137
138     act.sa_handler = DYNINSTalarmExpire;
139     act.sa_flags   = 0;
140
141     /* for AIX - default (non BSD) library does not restart - jkh 7/26/95 */
142 #if defined(SA_RESTART)
143     act.sa_flags  |= SA_RESTART;
144 #endif
145
146     sigfillset(&act.sa_mask);
147
148 #if defined(i386_unknown_solaris2_5) || defined(rs6000_ibm_aix4_1) 
149     /* we need to catch SIGTRAP inside the alarm handler */    
150     sigdelset(&act.sa_mask, SIGTRAP);
151 #endif
152
153     if (sigaction(SIGALRM, &act, 0) == -1) {
154         perror("sigaction(SIGALRM)");
155         abort();
156     }
157
158     it.it_value.tv_sec     = interval / 1000000;
159     it.it_value.tv_usec    = interval % 1000000;
160     it.it_interval.tv_sec  = interval / 1000000;
161     it.it_interval.tv_usec = interval % 1000000;
162
163     if (setitimer(ITIMER_REAL, &it, 0) == -1) {
164         perror("setitimer");
165         abort();
166     }
167 }
168 #endif
169
170
171 \f
172
173
174 static int DYNINST_trace_fd = -1; /* low-level version of DYNINSTtraceFp */
175 static FILE* DYNINSTtraceFp = 0;
176
177
178 /************************************************************************
179  * void DYNINSTflushTrace(void)
180  *
181  * flush any accumulated traces.
182 ************************************************************************/
183
184 void
185 DYNINSTflushTrace(void) {
186     if (DYNINSTtraceFp) fflush(DYNINSTtraceFp);
187 }
188
189
190 /************************************************************************
191  * void DYNINSwriteTrace(void)
192  *
193  * write data on the trace stream
194 ************************************************************************/
195
196 int
197 DYNINSTwriteTrace(void *buffer, unsigned count) {
198     int ret;
199     assert(DYNINSTtraceFp);
200     while (1) {
201       errno=0;
202       ret = fwrite(buffer, count, 1, DYNINSTtraceFp);
203       if (errno || ret!=1) {
204         if (errno==EINTR) {
205           printf("(pid=%d) fwrite interrupted, trying again...\n",(int) getpid());
206         } else {
207           perror("unable to write trace record");
208           printf("disabling further data logging, pid=%d\n", (int) getpid());
209           fflush(stdout);
210           return 0;
211         }
212       }
213       else
214         return 1;
215     }
216 }
217
218 /***********************************************************************/
219
220 #include <sys/types.h>
221 #include <sys/socket.h>
222 #include <sys/un.h>
223 extern char *sys_errlist[];
224
225 /************************************************************************
226  * static int connectToDaemon(int paradyndPid)
227  *
228  * get a connection to a paradyn daemon for the trace stream
229  *
230  * uses a UNIX domain STREAM socket
231 ************************************************************************/
232
233 static int connectToDaemon(int paradyndPid) {
234   /* uses paradyndPid to obtain a UNIX STREAM socket address to open. */
235
236   int sock_fd;
237   struct sockaddr_un sadr;
238
239   char path[100];
240   sprintf(path, "%sparadynd.%d", P_tmpdir, paradyndPid); // P_tmpdir in <stdio.h>
241
242   sock_fd = socket(PF_UNIX, SOCK_STREAM, 0);
243   if (sock_fd < 0) {
244     perror("DYNINST connectToDaemon() socket()");
245     abort();
246   }
247
248   sadr.sun_family = PF_UNIX;
249   strcpy(sadr.sun_path, path);
250   if (connect(sock_fd, (struct sockaddr *) &sadr, sizeof(sadr)) < 0) {
251     perror("DYNINST connectToDaemon() connect()");
252     abort();
253   }
254
255   return sock_fd;
256 }
257
258
259 /************************************************************************
260  * DYNINSTinitTrace(int daemon_addr)
261  *
262  * initializes the trace stream. daemon_addr is a platform dependent value
263  * that is used to create a connection. If daemon_addr is -1, we assume
264  * that the trace stream is already open (by the daemon, when it started
265  * this process). For posix systems, daemon_addr is the pid of the paradynd 
266  * daemon
267 ************************************************************************/
268
269 void DYNINSTinitTrace(int daemon_addr) {
270   if (daemon_addr == -1) {
271     /* this process was started by the paradynd, which set up a pipe on fd 3 */
272     DYNINST_trace_fd = 3;
273 #ifdef rs6000_ibm_aix4_1
274     DYNINSTtraceFp = fdopen(dup(DYNINST_trace_fd), "w");
275 #else
276     DYNINSTtraceFp = fdopen(syscall(SYS_dup,DYNINST_trace_fd), "w");
277 #endif
278     if (!DYNINSTtraceFp) {
279       perror("DYNINSTinitTrace: fdopen()");
280       abort();
281     }
282   } else {
283     /* fork or attach, get a connection to the daemon */
284     DYNINST_trace_fd = connectToDaemon(daemon_addr);
285     assert(DYNINST_trace_fd != -1);
286
287 #ifdef rs6000_ibm_aix4_1
288     DYNINSTtraceFp = fdopen(dup(DYNINST_trace_fd), "w"); 
289 #else
290     DYNINSTtraceFp = fdopen(syscall(dup,DYNINST_trace_fd), "w");
291 #endif
292     assert(DYNINSTtraceFp);
293   }
294   
295 }
296
297
298 void DYNINSTcloseTrace() {
299   fclose(DYNINSTtraceFp);
300   close(DYNINST_trace_fd);
301 }
302
303
304
305
306 /**********************************************************************
307  * Shared memory sampling functions 
308  * TODO: these functions should be prefixed by DYNINST
309 ***********************************************************************/
310
311 #ifdef SHM_SAMPLING
312 int shm_create_existing(key_t theKey, unsigned theSize) {
313    /* "create" segment (it already exists; paradynd did the real creating) but don't
314       attach; returns seg id */
315
316    int segid = shmget(theKey, theSize, 0666); // note no IPC_CREAT or IPC_EXCL flags
317    if (segid == -1) {
318        perror("shmget");
319        fprintf(stderr, "DYNINSTinit cannot shmget for key %d, size %u\n",
320                (int)theKey, theSize);
321        return -1;
322    }
323
324    return segid;
325 }
326
327 void *shm_attach(int shmid) {
328    void *result = shmat(shmid, NULL, 0);
329    if (result == (void *)-1) {
330        perror("DYNINSTinit: cannot shmat");
331        return NULL;
332    }
333
334    return result;
335 }
336
337 void shm_detach(void *shmSegPtr) {
338    (void)shmdt(shmSegPtr);
339 }
340
341 void *shm_detach_reattach_overlap(int newshmid, void *shmSegPtr) {
342    /* returns NULL on success (attached at same location),
343       (void*)-1 on total failure, and
344       a new address on partial failure (attached, but not at same location)
345     */
346
347    int success = 1; /* success, so far */
348    void *newAttachedAtPtr = NULL;
349
350    int detach_result = shmdt(shmSegPtr);
351    if (detach_result == -1) {
352       perror("shm_detach_reattach_overlap shmdt");
353       success = 0; /* failure; don't try to attach at same loc */
354    }
355
356    if (success) {
357       newAttachedAtPtr = shmat(newshmid, shmSegPtr, 0);
358       if (newAttachedAtPtr == (void*)-1) {
359          perror("shm_detach_reattach_overlap: cannot shmat");
360          success = 0; /* couldn't attach at same loc */
361       }
362    }
363
364    if (success)
365       return NULL; /* attached, and at the same location */
366    else {
367       /* couldn't attach at same location, so attach at a different location */
368       newAttachedAtPtr = shmat(newshmid, NULL, 0);
369       if (newAttachedAtPtr == (void*)-1)
370          /* this is unexpected...would have though that at least this would work */
371          perror("shm_detach_reattach_overlap: cannot shmat2");
372
373       return newAttachedAtPtr; /* -1 on total failure; an address on partial */
374    }
375 }
376
377
378 void *DYNINST_shm_init(int theKey, int shmSegNumBytes, int *the_id) {
379
380   int the_shmSegShmId;
381   void *the_shmSegAttachedPtr;
382
383   /* note: error checking needs to be beefed up here: */
384    
385   the_shmSegShmId = shm_create_existing(theKey, shmSegNumBytes); /* -1 on error */
386   if (the_shmSegShmId == -1) {
387      /* note: in theory, when we get a shm error on startup, it would be nice
388               to automatically "downshift" into the SIGALRM non-shm-sampling
389               code.  Not yet implemented. */
390      fprintf(stderr, "DYNINSTinit failed because shm_create_existing failed.\n");
391      fprintf(stderr, "DYNINST program startup failed...exiting program now.\n");
392      exit(5);
393   }
394
395   the_shmSegAttachedPtr = shm_attach(the_shmSegShmId); /* NULL on error */
396   if (the_shmSegAttachedPtr == NULL) {
397      /* see above note... */
398      fprintf(stderr, "DYNINSTinit failed because shm_attach failed.\n");
399      fprintf(stderr, "DYNINST program startup failed...exiting program now.\n");
400      exit(5);
401   }
402   *the_id = the_shmSegShmId; 
403   return the_shmSegAttachedPtr;
404
405 }
406
407 extern int DYNINST_shmSegKey;
408 extern int DYNINST_shmSegNumBytes;
409 extern int DYNINST_shmSegShmId;
410 extern void *DYNINST_shmSegAttachedPtr;
411
412 void shmsampling_printf(const char *fmt, ...) {
413 #ifdef SHM_SAMPLING_DEBUG
414    va_list args;
415    va_start(args, fmt);
416
417    vfprintf(stderr, fmt, args);
418
419    va_end(args);
420
421    fflush(stderr);
422 #endif
423 }
424
425
426 void pickNewShmSegBaseKey(key_t *resultKey,
427                           int *resultSegId) {
428    /* picks an avail shm seg and creates it.  Doesn't attach to it, though */
429
430    *resultKey = DYNINST_shmSegKey; /* as good a place to start as any... */
431
432    while (1) {
433       /* permissions chosen s.t. the request will fail if already exists */
434       int permissions = 0666 | IPC_CREAT | IPC_EXCL;
435          /* using IPC_EXCL ensure failure if already-exists */
436       int failure;
437
438       *resultSegId = shmget(*resultKey, DYNINST_shmSegNumBytes, permissions);
439
440       /* successful? */
441       failure = (*resultSegId == -1);
442
443       /* If successful, then keep the segments and update result vrbles */
444       if (!failure)
445          return;
446
447       /* On failure, we assume the shmget() didn't create anything. */
448       /* So, all we need to do is bump the key and retry... */
449       (*resultKey)++;
450    }
451 }
452
453 void makeNewShmSegCopy(void) {
454    /* detach from old shm segment, create new segment (IN THE SAME LOCATION AS THE OLD
455       ONE(*)) */
456    /* (*) the new shm segment MUST be in the same location as the old one, or else
457           any and all mini-tramps will be pointing to invalid addresses in the child
458           process! (the shm seg will appear to have moved) */
459
460    /* question: we detach from the old seg; should we also destroy it?  No, certainly
461       not, since paradynd still cares about measuring the old process. */
462    /* note: we used to memcpy all data from the old seg to the new one.  Now, since
463       we must detach from the old one before creating the new one, we can't do that.
464       Instead. we let paradynd do that. */
465
466    key_t new_shmSegKey;
467    int new_shmSegShmId;
468    void *new_attachedAtPtr;
469
470    /* 1. Pick a new, unused, key: */
471    pickNewShmSegBaseKey(&new_shmSegKey, &new_shmSegShmId);
472       /* picks & creates new segment; doesn't attach to it though */
473
474    shmsampling_printf("d-f makeNewShmSegsCopy: did pickNewShmSegBaseKey; chose key %d\n",
475                       (int)new_shmSegKey);
476
477    /* 2. Attach to the seg, IN THE SAME LOCATION AS THE OLD ONE.  In order to
478          achieve this sleight of hand, we must detach from the old one first, and pass
479          an address param to shm_attach.  Luckily, this doesn't require destroying the
480          old segment --- a good thing, since we mustn't do that (paradynd still cares
481          about measuring the parent!) */
482
483    new_attachedAtPtr = shm_detach_reattach_overlap(new_shmSegShmId,
484                                                    DYNINST_shmSegAttachedPtr);
485    if (new_attachedAtPtr == (void*)-1) {
486       /* total failure; could not attach */
487       fprintf(stderr, "makeNewShmSegCopy: failed to attach to new segment at all.\n");
488       abort();
489    }
490    else if (new_attachedAtPtr != NULL) {
491       /* partial failure; could not attach in the same location; could only attach at a
492          different location.  For now at least, this is as bad as a total failure */
493       fprintf(stderr, "makeNewShmSegCopy: could not attach to new segment in the same location as the old one.\n");
494       abort();
495    }
496
497    shmsampling_printf("d-f makeNewShmSegsCopy pid=%d: attached to new seg key=%d IN SAME LOC!\n", (int)getpid(), new_shmSegKey);
498    shmsampling_printf("d-f makeNewShmSegsCopy: also, detached from old seg.\n");
499
500    /* 3. Copy data from the old shm seg the new one */
501    /* (We don't [and can't] do this here any more, since we've already detached from the
502       old segment.  It was always a toss-up whether to let paradynd do the memcpy.
503       Now it must; and it does.) */
504
505    /* 4. update important global variables; the key and shmid change; the sizes and the
506          attached location doesn't change */
507    DYNINST_shmSegKey = new_shmSegKey;
508    DYNINST_shmSegShmId = new_shmSegShmId;
509    /* DYNINST_shmSegAttachedPtr = new_shmSegAttachedPtr; MUSTN'T CHANGE */
510
511    shmsampling_printf("d-f makeNewShmSegsCopy: done.\n");
512 }
513 #endif
514
515
516
517
518 \f
519
520
521 /*
522  * Return the number of bytes in a message hdr iovect.
523  *
524  */
525 int
526 DYNINSTgetMsgVectBytes(struct msghdr *msg)
527 {
528     int i;
529     int count;
530
531     for (i=0, count=0; i < msg->msg_iovlen; i++) {
532         count += msg->msg_iov[i].iov_len;
533     }
534     return count;
535 }
536
537 #define stache_blk_align(va)    ((void *)((unsigned)va & ~(STACHE_BLK_SIZE-1)))
538 #define STACHE_BLK_SIZE          stache_blk_size
539
540 //Blizzard
541 int stache_blk_size ;
542 void
543 DYNINSTreportNewMem(char *data_structure, void *va, int memory_size, int blk_size)
544 /*
545  *
546  */
547 {
548     void *align_va ;
549     struct _traceMemory newRes;
550
551     stache_blk_size = blk_size ;
552     align_va = stache_blk_align(va) ;    /* Do I need to align them?*/
553
554         printf("DYNINSTreportNewMem is called...\n") ;
555 #ifdef COSTTEST
556     time64 startT,endT;
557     startT=DYNINSTgetCPUtime();
558 #endif
559         memset(&newRes, '\0', sizeof(newRes));
560         sprintf(newRes.name, "%s", data_structure);
561         newRes.va = (int)align_va ;
562         newRes.memSize = memory_size ;
563         newRes.blkSize = blk_size ;
564         DYNINSTgenerateTraceRecord(0, TR_NEW_MEMORY, 
565                                 sizeof(struct _traceMemory), 
566                                 &newRes, 1, 0.0, 0.0);
567
568 #ifdef COSTTEST
569     endT=DYNINSTgetCPUtime();
570     DYNINSTtest[8]+=endT-startT;
571     DYNINSTtestN[8]++;
572 #endif
573 }
574
575 int 
576 fallIn(int addr, int lower, int upper)
577 {
578         return (addr<=upper && addr >= lower) ;
579 }