1: /* 2: * Copyright (c) 1987 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifdef LIBC_SCCS 8: <@(#)mcount.s 1.1 (Berkeley) 5/2/87\0> 9: .even 10: #endif LIBC_SCCS 11: 12: /* 13: * Count subroutine calls during simple (non-gprof) profiling. This file is 14: * appended to the compiled assembly output of mon.c. 15: * 16: * struct cnt { 17: * int (*pc)(); / address of function 18: * long ncall; / number of times _foo entered 19: * } 20: * 21: * mcount(cntp::r0) 22: * long **cntp; 23: * 24: * Mcount is called with a pointer to a function's local call count pointer in 25: * r0. On first entry, mcount allocates a (struct cnt) and initializes it with 26: * the function's base segment address and points the functions local call 27: * counter pointer just past the structure's ncall field. (we do this so we 28: * can do long increments slightly faster) 29: * 30: * The C compiler generates the following preamble for every function 31: * compiled with profiling: 32: * 33: * .data 34: * 1: _foo+1 35: * .text 36: * 37: * _foo: / unique name of foo (always in base) 38: * ~foo: / real address of foo 39: * +0 jsr r5,csv / perform standard C entry 40: * +4 mov $1b,r0 / point to local call counter pointer 41: * +8 jsr pc,mcount / and have mcount do its thing 42: * +12 ... / first `real' word of ~foo 43: * 44: * Function and ncall field addresses are always even so the "_foo+1" doesn't 45: * destroy information and can be used to determine a first call to mcount. 46: * 47: * Note that because we now use functions' base segment address rather than 48: * our own return address (as was done in the past) and because the call to 49: * mcount is after that to csv, profiling now works for overlaid objects. 50: * Only static routines in overlays which are assigned the same address by 51: * the loader may be counted incorrectly. 52: */ 53: #include "../sys/SYS.h" 54: #undef PROF 55: 56: .text 57: ASENTRY(mcount) 58: tst _countbase / buffer set up yet? 59: beq 2f / nope, just exit 60: mov (r0),r1 / cnt struct allocated yet? 61: bit $1,r1 62: bne 3f / nope, grab one 63: 1: 64: add $1,-(r1) / increment *(*cnt-1) 65: adc -(r1) 66: 2: 67: rts pc / and return 68: 3: 69: mov _countbase,r1 70: cmp r1,_countend / no, out of cnt structs? 71: bhis 3f / yes, output error message 72: mov (r0),(r1) / save _foo 73: bic $1,(r1)+ 74: cmp (r1)+,(r1)+ / move on to next cnt struct and 75: mov r1,_countbase / save in _countbase 76: mov r1,(r0) / save pointer to &ncall+1 in *cntp 77: br 1b / increment ncall (to 1) 78: 3: 79: mov $9f-8f,-(sp) / ran out cnt structs, output an 80: mov $8f,-(sp) / error message 81: mov $2,-(sp) 82: tst -(sp) / simulate return address stack 83: SYS(write) / spacing and perform write (we / / trap 4 -> [kernel] -> syscall() -> via sysent[] -> handler: write / 84: add $8.,sp / have to do the syscall because 85: rts pc / _write calls mcount) 86: 87: .data 88: 8: <mcount: counter overflow\n> 89: 9: 90: .text