xref: /freebsd/sys/gnu/gcov/gcov_subr.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
15426539cSMatt Macy /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
35426539cSMatt Macy  *
45426539cSMatt Macy  * Copyright (c) 2019, Matthew Macy <mmacy@freebsd.org>
55426539cSMatt Macy  *
65426539cSMatt Macy  * Redistribution and use in source and binary forms, with or without
75426539cSMatt Macy  * modification, are permitted provided that the following conditions
85426539cSMatt Macy  * are met:
95426539cSMatt Macy  * 1. Redistributions of source code must retain the above copyright
105426539cSMatt Macy  *    notice, this list of conditions and the following disclaimer.
115426539cSMatt Macy  * 2. Redistributions in binary form must reproduce the above copyright
125426539cSMatt Macy  *    notice, this list of conditions and the following disclaimer in the
135426539cSMatt Macy  *    documentation and/or other materials provided with the distribution.
145426539cSMatt Macy  *
155426539cSMatt Macy  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
165426539cSMatt Macy  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175426539cSMatt Macy  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185426539cSMatt Macy  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
195426539cSMatt Macy  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205426539cSMatt Macy  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215426539cSMatt Macy  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225426539cSMatt Macy  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235426539cSMatt Macy  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245426539cSMatt Macy  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255426539cSMatt Macy  * SUCH DAMAGE.
265426539cSMatt Macy  *
275426539cSMatt Macy  */
285426539cSMatt Macy 
295426539cSMatt Macy #include <sys/types.h>
305426539cSMatt Macy #include <sys/systm.h>
315426539cSMatt Macy #include <sys/param.h>
325426539cSMatt Macy #include <sys/sbuf.h>
335426539cSMatt Macy 
345426539cSMatt Macy #include <sys/queue.h>
355426539cSMatt Macy #include <sys/linker.h>
365426539cSMatt Macy #include <sys/module.h>
375426539cSMatt Macy #include <sys/eventhandler.h>
385426539cSMatt Macy #include <sys/kernel.h>
395426539cSMatt Macy #include <sys/malloc.h>
405426539cSMatt Macy #include <sys/syslog.h>
415426539cSMatt Macy #include <sys/proc.h>
425426539cSMatt Macy #include <sys/sched.h>
435426539cSMatt Macy #include <sys/syslog.h>
445426539cSMatt Macy #include <sys/sysctl.h>
455426539cSMatt Macy #include <gnu/gcov/gcov.h>
465426539cSMatt Macy #include <sys/queue.h>
475426539cSMatt Macy #include "linker_if.h"
485426539cSMatt Macy 
495426539cSMatt Macy 
505426539cSMatt Macy static void gcov_invoke_ctors(void);
515426539cSMatt Macy static int gcov_ctors_done;
525426539cSMatt Macy int gcov_events_enabled;
535426539cSMatt Macy 
545426539cSMatt Macy static int
gcov_stats_reset_sysctl(SYSCTL_HANDLER_ARGS)555426539cSMatt Macy gcov_stats_reset_sysctl(SYSCTL_HANDLER_ARGS)
565426539cSMatt Macy {
575426539cSMatt Macy 	int error, v;
585426539cSMatt Macy 
595426539cSMatt Macy 	v = 0;
605426539cSMatt Macy 	error = sysctl_handle_int(oidp, &v, 0, req);
615426539cSMatt Macy 	if (error)
625426539cSMatt Macy 		return (error);
635426539cSMatt Macy 	if (req->newptr == NULL)
645426539cSMatt Macy 		return (error);
655426539cSMatt Macy 	if (v == 0)
665426539cSMatt Macy 		return (0);
675426539cSMatt Macy 	gcov_stats_reset();
685426539cSMatt Macy 
695426539cSMatt Macy 	return (0);
705426539cSMatt Macy }
715426539cSMatt Macy 
725426539cSMatt Macy static int
gcov_stats_enable_sysctl(SYSCTL_HANDLER_ARGS)735426539cSMatt Macy gcov_stats_enable_sysctl(SYSCTL_HANDLER_ARGS)
745426539cSMatt Macy {
755426539cSMatt Macy 	int error, v;
765426539cSMatt Macy 
775426539cSMatt Macy 	v = gcov_events_enabled;
785426539cSMatt Macy 	error = sysctl_handle_int(oidp, &v, v, req);
795426539cSMatt Macy 	if (error)
805426539cSMatt Macy 		return (error);
815426539cSMatt Macy 	if (req->newptr == NULL)
825426539cSMatt Macy 		return (error);
835426539cSMatt Macy 	if (v == gcov_events_enabled)
845426539cSMatt Macy 		return (0);
855426539cSMatt Macy 	//gcov_events_reset();
865426539cSMatt Macy 	gcov_events_enabled = !!v;
875426539cSMatt Macy 	if (!gcov_ctors_done)
885426539cSMatt Macy 		gcov_invoke_ctors();
895426539cSMatt Macy 	if (gcov_events_enabled)
905426539cSMatt Macy 		gcov_enable_events();
915426539cSMatt Macy 
925426539cSMatt Macy 	return (0);
935426539cSMatt Macy }
945426539cSMatt Macy 
955426539cSMatt Macy int
within_module(vm_offset_t addr,module_t mod)965426539cSMatt Macy within_module(vm_offset_t addr, module_t mod)
975426539cSMatt Macy {
985426539cSMatt Macy 	linker_file_t link_info;
995426539cSMatt Macy 	vm_offset_t mod_addr;
1005426539cSMatt Macy 	size_t mod_size;
1015426539cSMatt Macy 
1025426539cSMatt Macy 	link_info = module_file(mod);
1035426539cSMatt Macy 	mod_addr = (vm_offset_t)link_info->address;
1045426539cSMatt Macy 	mod_size = link_info->size;
1055426539cSMatt Macy 	if (addr >= mod_addr && addr < mod_addr + mod_size)
1065426539cSMatt Macy 		return (1);
1075426539cSMatt Macy 	return (0);
1085426539cSMatt Macy }
1095426539cSMatt Macy 
1105426539cSMatt Macy 
1115426539cSMatt Macy 
1125426539cSMatt Macy #define GCOV_PREFIX "_GLOBAL__sub_I_65535_0_"
1135426539cSMatt Macy 
1145426539cSMatt Macy static int
gcov_invoke_ctor(const char * name,void * arg)1155426539cSMatt Macy gcov_invoke_ctor(const char *name, void *arg)
1165426539cSMatt Macy {
1175426539cSMatt Macy 	void (*ctor)(void);
1185426539cSMatt Macy 	c_linker_sym_t sym;
1195426539cSMatt Macy 	linker_symval_t symval;
1205426539cSMatt Macy 	linker_file_t lf;
1215426539cSMatt Macy 
1225426539cSMatt Macy 	if (strstr(name, GCOV_PREFIX) == NULL)
1235426539cSMatt Macy 		return (0);
1245426539cSMatt Macy 	lf = arg;
1255426539cSMatt Macy 	LINKER_LOOKUP_SYMBOL(lf, name, &sym);
1265426539cSMatt Macy 	LINKER_SYMBOL_VALUES(lf, sym, &symval);
1275426539cSMatt Macy 	ctor = (void *)symval.value;
1285426539cSMatt Macy 	ctor();
1295426539cSMatt Macy 	return (0);
1305426539cSMatt Macy }
1315426539cSMatt Macy 
1325426539cSMatt Macy static int
gcov_invoke_lf_ctors(linker_file_t lf,void * arg __unused)1335426539cSMatt Macy gcov_invoke_lf_ctors(linker_file_t lf, void *arg __unused)
1345426539cSMatt Macy {
1355426539cSMatt Macy 
1365426539cSMatt Macy 	printf("%s processing file: %s\n", __func__, lf->filename);
1375426539cSMatt Macy 	LINKER_EACH_FUNCTION_NAME(lf, gcov_invoke_ctor, lf);
1385426539cSMatt Macy 	return (0);
1395426539cSMatt Macy }
1405426539cSMatt Macy 
1415426539cSMatt Macy static void
gcov_invoke_ctors(void)1425426539cSMatt Macy gcov_invoke_ctors(void)
1435426539cSMatt Macy {
1445426539cSMatt Macy 
1455426539cSMatt Macy 	gcov_fs_init();
1465426539cSMatt Macy 
1475426539cSMatt Macy 	linker_file_foreach(gcov_invoke_lf_ctors, NULL);
1485426539cSMatt Macy 	gcov_ctors_done = 1;
1495426539cSMatt Macy }
1505426539cSMatt Macy 
1515426539cSMatt Macy static int
gcov_init(void * arg __unused)1525426539cSMatt Macy gcov_init(void *arg __unused)
1535426539cSMatt Macy {
1545426539cSMatt Macy 	EVENTHANDLER_REGISTER(module_unload, gcov_module_unload, NULL, 0);
1555426539cSMatt Macy 	gcov_enable_events();
1565426539cSMatt Macy 	return (0);
1575426539cSMatt Macy }
1585426539cSMatt Macy 
1595426539cSMatt Macy SYSINIT(gcov_init, SI_SUB_EVENTHANDLER, SI_ORDER_ANY, gcov_init, NULL);
1605426539cSMatt Macy 
1617029da5cSPawel Biernacki static SYSCTL_NODE(_debug, OID_AUTO, gcov, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
1625426539cSMatt Macy     "gcov code coverage");
1637029da5cSPawel Biernacki SYSCTL_PROC(_debug_gcov, OID_AUTO, reset,
1647029da5cSPawel Biernacki     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0,
1657029da5cSPawel Biernacki     gcov_stats_reset_sysctl, "I",
1667029da5cSPawel Biernacki     "Reset all profiling counts");
1677029da5cSPawel Biernacki SYSCTL_PROC(_debug_gcov, OID_AUTO, enable,
1687029da5cSPawel Biernacki     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, NULL, 0,
1697029da5cSPawel Biernacki     gcov_stats_enable_sysctl, "I",
1707029da5cSPawel Biernacki     "Enable code coverage");
171