Commit b54a432e authored by Lyude's avatar Lyude

Add the start of a kernel driver tracer, panwrap

This adds the start of a libwrap equivalent for panloader, called
panwrap. This library can be preloaded using LD_PRELOAD for any GL
application on android, and will log all of the ioctls made by the
respective application along with decoding it into human readable form
to the best of our ability.

Right now we only have decoding functions for the GET_VERSION ioctl and
the SET_FLAGS ioctl, but more are on the way!
parent 499d5191
......@@ -13,5 +13,6 @@ endif()
include_directories("include")
add_subdirectory(src)
add_subdirectory(panwrap)
# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab :
......@@ -23,10 +23,6 @@
#include <inttypes.h>
#include <panloader-util.h>
enum mali_func_id {
MALI_FUNC_GET_VERSION = 0,
};
/**
* Since these structs are passed to and from the kernel we need to make sure
* that we get the size of each struct to match exactly what the kernel is
......@@ -37,22 +33,77 @@ enum mali_func_id {
/**
* Header used by all ioctls
*/
union mali_ioctl_func_header {
union mali_ioctl_header {
/* [in] The ID of the UK function being called */
enum mali_func_id id :32;
uint32_t id :32;
/* [out] The return value of the UK function that was called */
uint32_t rc :32;
uint64_t :64;
} __attribute__((packed));
ASSERT_SIZEOF_TYPE(union mali_ioctl_func_header, 8);
ASSERT_SIZEOF_TYPE(union mali_ioctl_header, 8);
struct mali_ioctl_get_version {
union mali_ioctl_func_header header;
union mali_ioctl_header header;
uint16_t major; /* [out] */
uint16_t minor; /* [out] */
uint32_t :32;
} __attribute__((packed));
ASSERT_SIZEOF_TYPE(struct mali_ioctl_get_version, 16);
struct mali_ioctl_set_flags {
union mali_ioctl_header header;
uint32_t create_flags; /* [in] */
uint32_t :32;
} __attribute__((packed));
ASSERT_SIZEOF_TYPE(struct mali_ioctl_set_flags, 16);
/* For ioctl's we haven't written decoding stuff for yet */
typedef struct {
union mali_ioctl_header header;
} __ioctl_placeholder;
#define MALI_IOCTL_TYPE_BASE 0x80
#define MALI_IOCTL_TYPE_MAX 0x82
#define MALI_IOCTL_TYPE_MAX_OFFSET (MALI_IOCTL_TYPE_MAX - MALI_IOCTL_TYPE_BASE)
#define MALI_IOCTL_GET_VERSION (_IOWR(0x80, 0, struct mali_ioctl_get_version))
#define MALI_IOCTL_MEM_ALLOC (_IOWR(0x82, 0, __ioctl_placeholder))
#define MALI_IOCTL_MEM_IMPORT (_IOWR(0x82, 1, __ioctl_placeholder))
#define MALI_IOCTL_MEM_COMMIT (_IOWR(0x82, 2, __ioctl_placeholder))
#define MALI_IOCTL_MEM_QUERY (_IOWR(0x82, 3, __ioctl_placeholder))
#define MALI_IOCTL_MEM_FREE (_IOWR(0x82, 4, __ioctl_placeholder))
#define MALI_IOCTL_MEM_FLAGS_CHANGE (_IOWR(0x82, 5, __ioctl_placeholder))
#define MALI_IOCTL_MEM_ALIAS (_IOWR(0x82, 6, __ioctl_placeholder))
#define MALI_IOCTL_SYNC (_IOWR(0x82, 8, __ioctl_placeholder))
#define MALI_IOCTL_POST_TERM (_IOWR(0x82, 9, __ioctl_placeholder))
#define MALI_IOCTL_HWCNT_SETUP (_IOWR(0x82, 10, __ioctl_placeholder))
#define MALI_IOCTL_HWCNT_DUMP (_IOWR(0x82, 11, __ioctl_placeholder))
#define MALI_IOCTL_HWCNT_CLEAR (_IOWR(0x82, 12, __ioctl_placeholder))
#define MALI_IOCTL_GPU_PROPS_REG_DUMP (_IOWR(0x82, 14, __ioctl_placeholder))
#define MALI_IOCTL_FIND_CPU_OFFSET (_IOWR(0x82, 15, __ioctl_placeholder))
#define MALI_IOCTL_GET_VERSION_NEW (_IOWR(0x82, 16, struct mali_ioctl_get_version))
#define MALI_IOCTL_SET_FLAGS (_IOWR(0x82, 18, struct mali_ioctl_set_flags))
#define MALI_IOCTL_SET_TEST_DATA (_IOWR(0x82, 19, __ioctl_placeholder))
#define MALI_IOCTL_INJECT_ERROR (_IOWR(0x82, 20, __ioctl_placeholder))
#define MALI_IOCTL_MODEL_CONTROL (_IOWR(0x82, 21, __ioctl_placeholder))
#define MALI_IOCTL_KEEP_GPU_POWERED (_IOWR(0x82, 22, __ioctl_placeholder))
#define MALI_IOCTL_FENCE_VALIDATE (_IOWR(0x82, 23, __ioctl_placeholder))
#define MALI_IOCTL_STREAM_CREATE (_IOWR(0x82, 24, __ioctl_placeholder))
#define MALI_IOCTL_GET_PROFILING_CONTROLS (_IOWR(0x82, 25, __ioctl_placeholder))
#define MALI_IOCTL_SET_PROFILING_CONTROLS (_IOWR(0x82, 26, __ioctl_placeholder))
#define MALI_IOCTL_DEBUGFS_MEM_PROFILE_ADD (_IOWR(0x82, 27, __ioctl_placeholder))
#define MALI_IOCTL_JOB_SUBMIT (_IOWR(0x82, 28, __ioctl_placeholder))
#define MALI_IOCTL_DISJOINT_QUERY (_IOWR(0x82, 29, __ioctl_placeholder))
#define MALI_IOCTL_GET_CONTEXT_ID (_IOWR(0x82, 31, __ioctl_placeholder))
#define MALI_IOCTL_TLSTREAM_ACQUIRE_V10_4 (_IOWR(0x82, 32, __ioctl_placeholder))
#define MALI_IOCTL_TLSTREAM_TEST (_IOWR(0x82, 33, __ioctl_placeholder))
#define MALI_IOCTL_TLSTREAM_STATS (_IOWR(0x82, 34, __ioctl_placeholder))
#define MALI_IOCTL_TLSTREAM_FLUSH (_IOWR(0x82, 35, __ioctl_placeholder))
#define MALI_IOCTL_HWCNT_READER_SETUP (_IOWR(0x82, 36, __ioctl_placeholder))
#define MALI_IOCTL_SET_PRFCNT_VALUES (_IOWR(0x82, 37, __ioctl_placeholder))
#define MALI_IOCTL_SOFT_EVENT_UPDATE (_IOWR(0x82, 38, __ioctl_placeholder))
#define MALI_IOCTL_MEM_JIT_INIT (_IOWR(0x82, 39, __ioctl_placeholder))
#define MALI_IOCTL_TLSTREAM_ACQUIRE (_IOWR(0x82, 40, __ioctl_placeholder))
#endif /* __MALI_IOCTL_H__ */
project(panwrap)
set(SRCS panwrap-syscall.c panwrap-util.c)
add_library(panwrap SHARED ${SRCS})
/*
* © Copyright 2017 The BiOpenly Community
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <linux/ioctl.h>
#include <mali-ioctl.h>
#include "panwrap.h"
static pthread_mutex_t l = PTHREAD_MUTEX_INITIALIZER;
#define LOCK() pthread_mutex_lock(&l)
#define UNLOCK() pthread_mutex_unlock(&l)
#define LOG_PRE(format, ...) \
LOG("%s" format, "PRE ", ## __VA_ARGS__)
#define LOG_POST(format, ...) \
LOG("%s" format, "POST ", ## __VA_ARGS__)
struct device_info {
const char *name;
struct {
const char *name;
} ioctl_info[_IOC_NR(0xffffffff) + MALI_IOCTL_TYPE_MAX_OFFSET];
};
/* Every type of ioctl has a unique nr except for GET_VERSION. While
* GET_VERSION has a different dir then all of the other ioctl's, it
* unfortunately shares the same nr as MEM_ALLOC. So in order to ensure that
* we can have multiple ioctl's with the same nr so long as their dirs differ,
* we combine the type of the ioctl with the nr and map each ioctl with that
* instead
*/
#define IOCTL_MAP(request) (_IOC_NR(request) + (_IOC_TYPE(request) - \
MALI_IOCTL_TYPE_BASE))
#define IOCTL_INFO(n) \
[IOCTL_MAP(MALI_IOCTL_##n)] = { .name = #n }
static struct device_info mali_info = {
.name = "mali",
.ioctl_info = {
IOCTL_INFO(GET_VERSION),
IOCTL_INFO(MEM_ALLOC),
IOCTL_INFO(MEM_IMPORT),
IOCTL_INFO(MEM_COMMIT),
IOCTL_INFO(MEM_QUERY),
IOCTL_INFO(MEM_FREE),
IOCTL_INFO(MEM_FLAGS_CHANGE),
IOCTL_INFO(MEM_ALIAS),
IOCTL_INFO(SYNC),
IOCTL_INFO(POST_TERM),
IOCTL_INFO(HWCNT_SETUP),
IOCTL_INFO(HWCNT_DUMP),
IOCTL_INFO(HWCNT_CLEAR),
IOCTL_INFO(GPU_PROPS_REG_DUMP),
IOCTL_INFO(FIND_CPU_OFFSET),
IOCTL_INFO(GET_VERSION_NEW),
IOCTL_INFO(SET_FLAGS),
IOCTL_INFO(SET_TEST_DATA),
IOCTL_INFO(INJECT_ERROR),
IOCTL_INFO(MODEL_CONTROL),
IOCTL_INFO(KEEP_GPU_POWERED),
IOCTL_INFO(FENCE_VALIDATE),
IOCTL_INFO(STREAM_CREATE),
IOCTL_INFO(GET_PROFILING_CONTROLS),
IOCTL_INFO(SET_PROFILING_CONTROLS),
IOCTL_INFO(DEBUGFS_MEM_PROFILE_ADD),
IOCTL_INFO(JOB_SUBMIT),
IOCTL_INFO(DISJOINT_QUERY),
IOCTL_INFO(GET_CONTEXT_ID),
IOCTL_INFO(TLSTREAM_ACQUIRE_V10_4),
IOCTL_INFO(TLSTREAM_TEST),
IOCTL_INFO(TLSTREAM_STATS),
IOCTL_INFO(TLSTREAM_FLUSH),
IOCTL_INFO(HWCNT_READER_SETUP),
IOCTL_INFO(SET_PRFCNT_VALUES),
IOCTL_INFO(SOFT_EVENT_UPDATE),
IOCTL_INFO(MEM_JIT_INIT),
IOCTL_INFO(TLSTREAM_ACQUIRE),
},
};
#undef IOCTL_INFO
static int mali_fd = 0;
static inline const char *
ioctl_get_name(unsigned long int request)
{
const char *name = mali_info.ioctl_info[IOCTL_MAP(request)].name;
if (name)
return name;
else
return "???";
}
static void
ioctl_decode_pre_set_flags(unsigned long int request, void *ptr)
{
const struct mali_ioctl_set_flags *args = ptr;
LOG_PRE("\tcreate_flags = %08x\n", args->create_flags);
}
static void
ioctl_decode_pre(unsigned long int request, void *ptr)
{
switch (IOCTL_MAP(request)) {
case IOCTL_MAP(MALI_IOCTL_SET_FLAGS):
ioctl_decode_pre_set_flags(request, ptr);
break;
default:
break;
}
}
static void
ioctl_decode_post_get_version(unsigned long int request, void *ptr)
{
const struct mali_ioctl_get_version *args = ptr;
LOG_POST("\tmajor = %3d\n", args->major);
LOG_POST("\tminor = %3d\n", args->minor);
}
static void
ioctl_decode_post(unsigned long int request, void *ptr)
{
switch (IOCTL_MAP(request)) {
case IOCTL_MAP(MALI_IOCTL_GET_VERSION):
case IOCTL_MAP(MALI_IOCTL_GET_VERSION_NEW):
ioctl_decode_post_get_version(request, ptr);
break;
default:
break;
}
}
/**
* Overriden libc functions start here
*/
int
open(const char *path, int flags, ...)
{
mode_t mode = 0;
int ret;
PROLOG(open);
if (flags & O_CREAT) {
va_list args;
va_start(args, flags);
mode = (mode_t) va_arg(args, int);
va_end(args);
ret = orig_open(path, flags, mode);
} else {
ret = orig_open(path, flags);
}
LOCK();
if (ret != -1) {
if (strcmp(path, "/dev/mali0") == 0) {
LOG("/dev/mali0 fd == %d\n", ret);
mali_fd = ret;
} else if (strstr(path, "/dev/")) {
LOG("Unknown device %s opened at fd %d\n",
path, ret);
}
}
UNLOCK();
return ret;
}
int
close(int fd)
{
PROLOG(close);
LOCK();
if (fd > 0 && fd == mali_fd) {
LOG("/dev/mali0 closed\n");
mali_fd = 0;
}
UNLOCK();
return orig_close(fd);
}
/* XXX: Android has a messed up ioctl signature */
int ioctl(int fd, int request, ...)
{
const char *name;
union mali_ioctl_header *header;
PROLOG(ioctl);
int ioc_size = _IOC_SIZE(request);
int ret;
uint32_t func;
void *ptr;
if (ioc_size) {
va_list args;
va_start(args, request);
ptr = va_arg(args, void *);
va_end(args);
} else {
ptr = NULL;
}
if (fd && fd != mali_fd)
return orig_ioctl(fd, request, ptr);
LOCK();
name = ioctl_get_name(request);
header = ptr;
if (!ptr) { /* All valid mali ioctl's should have a specified arg */
LOG_PRE("<%-20s> (%02d) (%08x), has no arguments? Cannot decode :(\n",
name, _IOC_NR(request), request);
ret = orig_ioctl(fd, request, ptr);
LOG_POST("<%-20s> (%02d) (%08x) == %02d\n",
name, _IOC_NR(request), request, ret);
goto out;
}
func = header->id;
LOG_PRE("<%-20s> (%02d) (%08x) (%04d) (%03d)\n",
name, _IOC_NR(request), request, _IOC_SIZE(request), func);
ioctl_decode_pre(request, ptr);
ret = orig_ioctl(fd, request, ptr);
LOG_POST("<%-20s> (%02d) (%08x) (%04d) (%03d) == %02d, %02d\n",
name, _IOC_NR(request), request, _IOC_SIZE(request), func, ret,
header->rc);
ioctl_decode_post(request, ptr);
out:
UNLOCK();
return ret;
}
/*
* © Copyright 2017 The BiOpenly Community
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU licence.
*
* A copy of the licence is included with the program, and can also be obtained
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include "panwrap.h"
/**
* Literally grab the location of a symbol from libc so that we can change it
* to whatever we want
*/
void *
__rd_dlsym_helper(const char *name)
{
static void *libc_dl;
void *func;
if (!libc_dl)
libc_dl = dlopen("libc.so", RTLD_LAZY);
if (!libc_dl) {
fprintf(stderr, "Failed to dlopen libc: %s\n", dlerror());
exit(-1);
}
func = dlsym(libc_dl, name);
if (!func) {
fprintf(stderr, "Failed to find %s: %s\n", name, dlerror());
exit(-1);
}
return func;
}
/*
* © Copyright 2017 The BiOpenly Community
*
* This program is free software and is provided to you under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation, and any use by you of this program is subject to the terms
* of such GNU license.
*
* A copy of the license is included with the program, and can also be obtained
* from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
/*
* Various bits and pieces of this borrowed from the freedreno project, which
* borrowed from the lima project.
*/
#ifndef __WRAP_H__
#define __WRAP_H__
#include <dlfcn.h>
void * __rd_dlsym_helper(const char *name);
#define PROLOG(func) \
static typeof(func) *orig_##func = NULL; \
if (!orig_##func) \
orig_##func = __rd_dlsym_helper(#func); \
#define LOG(format, ...) \
printf("%s" format, "panwrap: ", ## __VA_ARGS__)
#endif /* __WRAP_H__ */
......@@ -26,7 +26,7 @@ pandev_get_driver_version(int fd, unsigned *major, unsigned *minor)
int rc;
/* So far this seems to be the only ioctl that uses 0x80 for dir */
rc = ioctl(fd, _IOWR(0x80, MALI_FUNC_GET_VERSION, args), &args);
rc = ioctl(fd, MALI_IOCTL_GET_VERSION, &args);
if (rc)
return rc;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment