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