1 /*
2  *            Debugger
3  *
4  *    Copyright 1990-2009 Green Hills Software, Inc.
5  *
6  *    This program is the property of Green Hills Software, Inc,
7  *    its contents are proprietary information and no part of it
8  *    is to be disclosed to anyone except employees of Green Hills
9  *    Software, Inc., or as agreed in writing signed by the President
10  *    of Green Hills Software, Inc.
11  */
12 /* ind_bcnt.c: compiler internal functions for Block Coverage Profiling. */
13 
14 #if defined(EMBEDDED) || defined(__OSE)
15 
16 #include "indos.h"
17 #include "ind_io.h"
18 #include "ind_exit.h"
19 #include "ind_thrd.h"
20 
21 struct blk { void (*addr)(void); unsigned int cnt; };
22 struct bhdr { int len; struct blk *info; int inserted; struct bhdr *next; };
23 static struct bhdr *blocklisthead;
24 
25 /* Macro for printing errors */
26 #define PERROR(msg) write(2, msg, sizeof(msg)-1);
27 
28 /* File System I/O Calls to write the file to the host */
29 #if defined(__INTEGRITY) || defined(__INTEGRITY_SHARED_LIBS)
30 #define HOSTIO_CREAT hostio_creat
31 #define HOSTIO_WRITE write
32 #define HOSTIO_CLOSE close
33 #else
34 #define HOSTIO_CREAT __ghs_hostio_creat
35 #define HOSTIO_WRITE __ghs_hostio_write
36 #define HOSTIO_CLOSE __ghs_hostio_close
37 #endif
38 
39 /**
40  * Clears the coverage information.  This can be used as a command line
41  * procedure call from MULTI to make it possible to generate coverage
42  * information only for a specific interval in a run of a program.
43  * Stop the program, call __ghs_prof_clear_coverage(), run to another
44  * point, dump.
45  *
46  * The functions remain in the linked list so that any future block
47  * coverage data gathered within a function, such as a main loop,
48  * that is currently executing but that is not called again,
49  * will be output by __ghs_prof_dump_coverage.
50  *
51  */
__ghs_prof_clear_coverage(void)52 void __ghs_prof_clear_coverage(void)
53 {
54     int i;
55     struct bhdr *p, *next;
56 
57     for (p = blocklisthead; p; p = next) {
58 	next = p->next;
59 	if (p->len > 0) {
60 	    /* Reset all counts to 0 except the last block's count. */
61 	    for (i = 0; i < p->len - 1; i++)
62 		p->info[i].cnt = 0;
63 	    /* The last block's count can be either a special -1 marker or a
64 	       normal run count. */
65 	    if (p->info[p->len - 1].cnt != (unsigned int)-1)
66 		p->info[p->len - 1].cnt = 0;
67 	}
68     }
69 }
70 
71 #define _0644	0x1a4	/* MISRA C does not allow octal constants */
72 
73 /* This routine is global to allow it to be called from MULTI */
__ghs_prof_dump_coverage(void)74 void __ghs_prof_dump_coverage(void)
75 {
76     int fd;
77     struct bhdr *test;
78 
79     /*
80      * Use hostio, since the file belongs on the host system, not
81      * the target system.
82      */
83     fd = HOSTIO_CREAT("bmon.out", _0644);
84 
85     if (fd == -1) {
86 	PERROR("bcount: could not create bmon.out\n");
87 	return;
88     }
89     for (test = blocklisthead; test; test = test->next) {
90 	int contains_nonzero_count = 0;
91 	int i;
92 	int cnt;
93 	if (test->len > 0) {
94 	    for (i = 0; i < test->len - 1; i++) {
95 		if (test->info[i].cnt != 0) {
96 		    contains_nonzero_count = 1;
97 		    break;
98 		}
99 	    }
100 	    /* The last block can have either a special -1 marker count or a
101 	       normal run count. */
102 	    if (test->info[test->len - 1].cnt != 0 &&
103 		    test->info[test->len - 1].cnt != (unsigned int)-1)
104 		contains_nonzero_count = 1;
105 	}
106 	/* Don't write out any block count data if no block in this function
107 	   has executed.  This can happen if __ghs_prof_clear_coverage was run,
108 	   as from the MULTI command "profilemode clear". */
109 	if(contains_nonzero_count == 0)
110 	    continue;
111 #if __PTR_BIT <= 32
112 	cnt = sizeof(struct blk)*test->len;
113 	if (HOSTIO_WRITE(fd, test->info, cnt) != cnt) {
114 	    PERROR("bcount: write failed for bmon.out\n");
115 	    HOSTIO_CLOSE(fd);
116 	    return;
117 	}
118 #else /* __PTR_BIT */
119 	cnt = sizeof(void *) + sizeof(int);
120 	for( i=0; i<test->len; i++ ) {
121 	    /* only write the packed data */
122 	    if(HOSTIO_WRITE(fd, &(test->info[i]), cnt) != cnt ) {
123 		PERROR("bcount: write failed for bmon.out\n");
124 		HOSTIO_CLOSE(fd);
125 		return;
126 	    }
127 	}
128 #endif /* __PTR_BIT */
129     }
130     HOSTIO_CLOSE(fd);
131 }
132 
__ghs_bcount(struct bhdr * routinfo,void (* routaddr)(void))133 void __ghs_bcount(struct bhdr *routinfo, void (*routaddr)(void))
134 {
135     __ghs_ProfileLock();
136     if (routinfo->inserted) {
137 	__ghs_ProfileUnlock();
138 	return;
139     }
140     if (!blocklisthead) {
141 	static struct __GHS_AT_EXIT gae;
142 	if (!gae.func) {
143 	    gae.func = __ghs_prof_dump_coverage;
144 	    __ghs_at_exit(&gae);
145 	}
146     }
147 
148     routinfo->inserted = 1;
149     routinfo->next = blocklisthead;
150     blocklisthead = routinfo;
151     __ghs_ProfileUnlock();
152 }
153 
154 #endif /* defined(EMBEDDED) */
155