mirror of
https://github.com/RGBCube/serenity
synced 2025-10-24 19:02:33 +00:00
This has several benefits: 1) We no longer just blindly derefence a null pointer in various places 2) We will get nicer runtime error messages if the current process does turn out to be null in the call location 3) GCC no longer complains about possible nullptr dereferences when compiling without KUBSAN
150 lines
4.3 KiB
C++
150 lines
4.3 KiB
C++
/*
|
|
* Copyright (c) 2021, Patrick Meyer <git@the-space.agency>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/Assertions.h>
|
|
#include <AK/NonnullOwnPtr.h>
|
|
#include <Kernel/Devices/KCOVDevice.h>
|
|
#include <Kernel/Devices/KCOVInstance.h>
|
|
#include <Kernel/FileSystem/FileDescription.h>
|
|
#include <LibC/sys/ioctl_numbers.h>
|
|
|
|
#include <Kernel/Panic.h>
|
|
|
|
namespace Kernel {
|
|
|
|
HashMap<ProcessID, KCOVInstance*>* KCOVDevice::proc_instance;
|
|
HashMap<ThreadID, KCOVInstance*>* KCOVDevice::thread_instance;
|
|
|
|
UNMAP_AFTER_INIT NonnullRefPtr<KCOVDevice> KCOVDevice::must_create()
|
|
{
|
|
return adopt_ref(*new KCOVDevice);
|
|
}
|
|
|
|
UNMAP_AFTER_INIT KCOVDevice::KCOVDevice()
|
|
: BlockDevice(30, 0)
|
|
{
|
|
proc_instance = new HashMap<ProcessID, KCOVInstance*>();
|
|
thread_instance = new HashMap<ThreadID, KCOVInstance*>();
|
|
dbgln("KCOVDevice created");
|
|
}
|
|
|
|
void KCOVDevice::free_thread()
|
|
{
|
|
auto thread = Thread::current();
|
|
auto tid = thread->tid();
|
|
|
|
auto maybe_kcov_instance = thread_instance->get(tid);
|
|
if (!maybe_kcov_instance.has_value())
|
|
return;
|
|
|
|
auto kcov_instance = maybe_kcov_instance.value();
|
|
VERIFY(kcov_instance->state == KCOVInstance::TRACING);
|
|
kcov_instance->state = KCOVInstance::OPENED;
|
|
thread_instance->remove(tid);
|
|
}
|
|
|
|
void KCOVDevice::free_process()
|
|
{
|
|
auto pid = Process::current().pid();
|
|
|
|
auto maybe_kcov_instance = proc_instance->get(pid);
|
|
if (!maybe_kcov_instance.has_value())
|
|
return;
|
|
|
|
auto kcov_instance = maybe_kcov_instance.value();
|
|
VERIFY(kcov_instance->state == KCOVInstance::OPENED);
|
|
kcov_instance->state = KCOVInstance::UNUSED;
|
|
proc_instance->remove(pid);
|
|
delete kcov_instance;
|
|
}
|
|
|
|
KResultOr<NonnullRefPtr<FileDescription>> KCOVDevice::open(int options)
|
|
{
|
|
auto pid = Process::current().pid();
|
|
if (proc_instance->get(pid).has_value())
|
|
return EBUSY; // This process already open()ed the kcov device
|
|
auto kcov_instance = new KCOVInstance(pid);
|
|
kcov_instance->state = KCOVInstance::OPENED;
|
|
proc_instance->set(pid, kcov_instance);
|
|
|
|
return File::open(options);
|
|
}
|
|
|
|
KResult KCOVDevice::ioctl(FileDescription&, unsigned request, Userspace<void*> arg)
|
|
{
|
|
KResult return_value = KSuccess;
|
|
auto thread = Thread::current();
|
|
auto tid = thread->tid();
|
|
auto pid = thread->pid();
|
|
auto maybe_kcov_instance = proc_instance->get(pid);
|
|
if (!maybe_kcov_instance.has_value())
|
|
return ENXIO; // This proc hasn't opened the kcov dev yet
|
|
auto kcov_instance = maybe_kcov_instance.value();
|
|
|
|
ScopedSpinLock lock(kcov_instance->lock);
|
|
switch (request) {
|
|
case KCOV_SETBUFSIZE: {
|
|
if (kcov_instance->state >= KCOVInstance::TRACING) {
|
|
return_value = EBUSY;
|
|
break;
|
|
}
|
|
return_value = kcov_instance->buffer_allocate((FlatPtr)arg.unsafe_userspace_ptr());
|
|
break;
|
|
}
|
|
case KCOV_ENABLE: {
|
|
if (kcov_instance->state >= KCOVInstance::TRACING) {
|
|
return_value = EBUSY;
|
|
break;
|
|
}
|
|
if (!kcov_instance->has_buffer()) {
|
|
return_value = ENOBUFS;
|
|
break;
|
|
}
|
|
VERIFY(kcov_instance->state == KCOVInstance::OPENED);
|
|
kcov_instance->state = KCOVInstance::TRACING;
|
|
thread_instance->set(tid, kcov_instance);
|
|
break;
|
|
}
|
|
case KCOV_DISABLE: {
|
|
auto maybe_kcov_instance = thread_instance->get(tid);
|
|
if (!maybe_kcov_instance.has_value()) {
|
|
return_value = ENOENT;
|
|
break;
|
|
}
|
|
VERIFY(kcov_instance->state == KCOVInstance::TRACING);
|
|
kcov_instance->state = KCOVInstance::OPENED;
|
|
thread_instance->remove(tid);
|
|
break;
|
|
}
|
|
default: {
|
|
return_value = EINVAL;
|
|
}
|
|
};
|
|
|
|
return return_value;
|
|
}
|
|
|
|
KResultOr<Memory::Region*> KCOVDevice::mmap(Process& process, FileDescription&, Memory::VirtualRange const& range, u64 offset, int prot, bool shared)
|
|
{
|
|
auto pid = process.pid();
|
|
auto maybe_kcov_instance = proc_instance->get(pid);
|
|
VERIFY(maybe_kcov_instance.has_value()); // Should happen on fd open()
|
|
auto kcov_instance = maybe_kcov_instance.value();
|
|
|
|
if (!kcov_instance->vmobject) {
|
|
return ENOBUFS; // Mmaped, before KCOV_SETBUFSIZE
|
|
}
|
|
|
|
return process.address_space().allocate_region_with_vmobject(
|
|
range, *kcov_instance->vmobject, offset, {}, prot, shared);
|
|
}
|
|
|
|
String KCOVDevice::device_name() const
|
|
{
|
|
return "kcov"sv;
|
|
}
|
|
|
|
}
|