2 * Copyright (c) 1996 Barton P. Miller
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.
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.
18 * (for other uses, please contact us at paradyn@cs.wisc.edu)
20 * All warranties, including without limitation, any warranty of
21 * merchantability or fitness for a particular purpose, are hereby
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.
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.
42 /************************************************************************
43 * RTposix.c: runtime instrumentation functions for generic posix.
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
50 * Revision 1.9 1995/03/10 19:39:42 hollings
51 * Fixed an ugly race condition in observed cost.
53 * Added the use of unix profil to compute the time spent in inst code.
56 ************************************************************************/
59 #include <sys/types.h>
74 #include <sys/socket.h>
77 #ifdef rs6000_ibm_aix4_1
79 #include <sys/syscall.h>
85 #include "rtinst/h/rtinst.h"
86 #include "rtinst/h/trace.h"
87 #include "util/h/sys.h"
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);
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 *);
106 /************************************************************************
107 * void DYNINSTbreakPoint(void)
110 ************************************************************************/
113 DYNINSTbreakPoint(void) {
114 kill(getpid(), SIGSTOP);
119 /************************************************************************
120 * void DYNINST_install_ualarm_interval(unsigned interval)
122 * an implementation of "ualarm" using the "setitimer" syscall.
123 * interval is in microseconds
124 ************************************************************************/
126 #if !defined(hppa1_1_hp_hpux)
127 extern void DYNINSTalarmExpire(int signo);
129 extern void DYNINSTalarmExpire(int signo, int code, struct sigcontext *scp);
134 DYNINST_install_ualarm(unsigned interval) {
136 struct sigaction act;
138 act.sa_handler = DYNINSTalarmExpire;
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;
146 sigfillset(&act.sa_mask);
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);
153 if (sigaction(SIGALRM, &act, 0) == -1) {
154 perror("sigaction(SIGALRM)");
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;
163 if (setitimer(ITIMER_REAL, &it, 0) == -1) {
174 static int DYNINST_trace_fd = -1; /* low-level version of DYNINSTtraceFp */
175 static FILE* DYNINSTtraceFp = 0;
178 /************************************************************************
179 * void DYNINSTflushTrace(void)
181 * flush any accumulated traces.
182 ************************************************************************/
185 DYNINSTflushTrace(void) {
186 if (DYNINSTtraceFp) fflush(DYNINSTtraceFp);
190 /************************************************************************
191 * void DYNINSwriteTrace(void)
193 * write data on the trace stream
194 ************************************************************************/
197 DYNINSTwriteTrace(void *buffer, unsigned count) {
199 assert(DYNINSTtraceFp);
202 ret = fwrite(buffer, count, 1, DYNINSTtraceFp);
203 if (errno || ret!=1) {
205 printf("(pid=%d) fwrite interrupted, trying again...\n",(int) getpid());
207 perror("unable to write trace record");
208 printf("disabling further data logging, pid=%d\n", (int) getpid());
218 /***********************************************************************/
220 #include <sys/types.h>
221 #include <sys/socket.h>
223 extern char *sys_errlist[];
225 /************************************************************************
226 * static int connectToDaemon(int paradyndPid)
228 * get a connection to a paradyn daemon for the trace stream
230 * uses a UNIX domain STREAM socket
231 ************************************************************************/
233 static int connectToDaemon(int paradyndPid) {
234 /* uses paradyndPid to obtain a UNIX STREAM socket address to open. */
237 struct sockaddr_un sadr;
240 sprintf(path, "%sparadynd.%d", P_tmpdir, paradyndPid); // P_tmpdir in <stdio.h>
242 sock_fd = socket(PF_UNIX, SOCK_STREAM, 0);
244 perror("DYNINST connectToDaemon() socket()");
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()");
259 /************************************************************************
260 * DYNINSTinitTrace(int daemon_addr)
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
267 ************************************************************************/
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");
276 DYNINSTtraceFp = fdopen(syscall(SYS_dup,DYNINST_trace_fd), "w");
278 if (!DYNINSTtraceFp) {
279 perror("DYNINSTinitTrace: fdopen()");
283 /* fork or attach, get a connection to the daemon */
284 DYNINST_trace_fd = connectToDaemon(daemon_addr);
285 assert(DYNINST_trace_fd != -1);
287 #ifdef rs6000_ibm_aix4_1
288 DYNINSTtraceFp = fdopen(dup(DYNINST_trace_fd), "w");
290 DYNINSTtraceFp = fdopen(syscall(dup,DYNINST_trace_fd), "w");
292 assert(DYNINSTtraceFp);
298 void DYNINSTcloseTrace() {
299 fclose(DYNINSTtraceFp);
300 close(DYNINST_trace_fd);
306 /**********************************************************************
307 * Shared memory sampling functions
308 * TODO: these functions should be prefixed by DYNINST
309 ***********************************************************************/
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 */
316 int segid = shmget(theKey, theSize, 0666); // note no IPC_CREAT or IPC_EXCL flags
319 fprintf(stderr, "DYNINSTinit cannot shmget for key %d, size %u\n",
320 (int)theKey, theSize);
327 void *shm_attach(int shmid) {
328 void *result = shmat(shmid, NULL, 0);
329 if (result == (void *)-1) {
330 perror("DYNINSTinit: cannot shmat");
337 void shm_detach(void *shmSegPtr) {
338 (void)shmdt(shmSegPtr);
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)
347 int success = 1; /* success, so far */
348 void *newAttachedAtPtr = NULL;
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 */
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 */
365 return NULL; /* attached, and at the same location */
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");
373 return newAttachedAtPtr; /* -1 on total failure; an address on partial */
378 void *DYNINST_shm_init(int theKey, int shmSegNumBytes, int *the_id) {
381 void *the_shmSegAttachedPtr;
383 /* note: error checking needs to be beefed up here: */
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");
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");
402 *the_id = the_shmSegShmId;
403 return the_shmSegAttachedPtr;
407 extern int DYNINST_shmSegKey;
408 extern int DYNINST_shmSegNumBytes;
409 extern int DYNINST_shmSegShmId;
410 extern void *DYNINST_shmSegAttachedPtr;
412 void shmsampling_printf(const char *fmt, ...) {
413 #ifdef SHM_SAMPLING_DEBUG
417 vfprintf(stderr, fmt, args);
426 void pickNewShmSegBaseKey(key_t *resultKey,
428 /* picks an avail shm seg and creates it. Doesn't attach to it, though */
430 *resultKey = DYNINST_shmSegKey; /* as good a place to start as any... */
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 */
438 *resultSegId = shmget(*resultKey, DYNINST_shmSegNumBytes, permissions);
441 failure = (*resultSegId == -1);
443 /* If successful, then keep the segments and update result vrbles */
447 /* On failure, we assume the shmget() didn't create anything. */
448 /* So, all we need to do is bump the key and retry... */
453 void makeNewShmSegCopy(void) {
454 /* detach from old shm segment, create new segment (IN THE SAME LOCATION AS THE OLD
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) */
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. */
468 void *new_attachedAtPtr;
470 /* 1. Pick a new, unused, key: */
471 pickNewShmSegBaseKey(&new_shmSegKey, &new_shmSegShmId);
472 /* picks & creates new segment; doesn't attach to it though */
474 shmsampling_printf("d-f makeNewShmSegsCopy: did pickNewShmSegBaseKey; chose key %d\n",
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!) */
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");
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");
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");
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.) */
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 */
511 shmsampling_printf("d-f makeNewShmSegsCopy: done.\n");
522 * Return the number of bytes in a message hdr iovect.
526 DYNINSTgetMsgVectBytes(struct msghdr *msg)
531 for (i=0, count=0; i < msg->msg_iovlen; i++) {
532 count += msg->msg_iov[i].iov_len;
537 #define stache_blk_align(va) ((void *)((unsigned)va & ~(STACHE_BLK_SIZE-1)))
538 #define STACHE_BLK_SIZE stache_blk_size
541 int stache_blk_size ;
543 DYNINSTreportNewMem(char *data_structure, void *va, int memory_size, int blk_size)
549 struct _traceMemory newRes;
551 stache_blk_size = blk_size ;
552 align_va = stache_blk_align(va) ; /* Do I need to align them?*/
554 printf("DYNINSTreportNewMem is called...\n") ;
557 startT=DYNINSTgetCPUtime();
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);
569 endT=DYNINSTgetCPUtime();
570 DYNINSTtest[8]+=endT-startT;
576 fallIn(int addr, int lower, int upper)
578 return (addr<=upper && addr >= lower) ;