Skip to content

Commit 8f7269f

Browse files
authored
Merge pull request #125 from leegao/val_layer
Add integration for validation layer via libgraphicsenv.so hijacking
2 parents 874082a + 521de8e commit 8f7269f

File tree

5 files changed

+186
-95
lines changed

5 files changed

+186
-95
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#include "graphics_env_hooks.h"
2+
#include <iostream>
3+
#include <vector>
4+
#include <string>
5+
#include <dlfcn.h>
6+
7+
extern "C" {
8+
#include "wrapper_log.h"
9+
#include "wrapper_debug.h"
10+
}
11+
12+
#define PATH "/data/data/com.winlator.cmod/files/imagefs/usr/lib"
13+
14+
extern "C"
15+
bool set_layer_paths() {
16+
void* handle = dlopen("libgraphicsenv.so", RTLD_NOW);
17+
#define LAYER_ERROR(fmt, ...) \
18+
WLOGE(fmt, ## __VA_ARGS__); \
19+
dlclose(handle); \
20+
return false
21+
22+
if (!handle) {
23+
LAYER_ERROR("Cannot open libgraphicsenv.so");
24+
}
25+
26+
#define FIND(var, sig, name) auto var = sig (dlsym(handle, name)); \
27+
if (!var) { \
28+
LAYER_ERROR("Cannot find symbol in libgraphicsenv.so: " #name); \
29+
} \
30+
WLOGD("Found " #name " in libgraphicsenv.so at %p", var);
31+
32+
FIND(getInstance, (void* (*)()), "_ZN7android11GraphicsEnv11getInstanceEv");
33+
FIND(getLayerPaths, (const std::string&(*)(void*)), "_ZN7android11GraphicsEnv13getLayerPathsEv");
34+
FIND(getAppNamespace, (void* (*)(void*)), "_ZN7android11GraphicsEnv15getAppNamespaceEv");
35+
FIND(setLayerPaths, (void (*)(void*, void*, const std::string)), "_ZN7android11GraphicsEnv13setLayerPathsEPNS_21NativeLoaderNamespaceENSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEE");
36+
37+
void* instance = getInstance();
38+
if (!instance) {
39+
LAYER_ERROR("GraphicsEnv::getInstance() failed");
40+
}
41+
42+
auto path = getLayerPaths(instance);
43+
if (!path.empty()) {
44+
if (path == PATH) {
45+
WLOGD("GraphicsEnv::mLayerPaths is already set correctly");
46+
dlclose(handle);
47+
return true;
48+
}
49+
LAYER_ERROR("GraphicsEnv::mLayerPaths is already set to %s, cannot perform hijacking", path.c_str());
50+
}
51+
void* app_namespace = getAppNamespace(instance);
52+
setLayerPaths(instance, app_namespace, PATH);
53+
path = getLayerPaths(instance);
54+
if (path != PATH) {
55+
LAYER_ERROR("GraphicsEnv::mLayerPaths failed to be set correctly, found %s", path.c_str());
56+
}
57+
58+
WLOGD("GraphicsEnv::mLayerPaths set to %s", path.c_str());
59+
return true;
60+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#pragma once
2+
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
bool set_layer_paths(void);
8+
9+
#ifdef __cplusplus
10+
}
11+
#endif

src/vulkan/wrapper/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ wrapper_files = files(
121121
'wrapper_debug.c',
122122
'wrapper_objects.c',
123123
'spirv_edit.cpp',
124+
'graphics_env_hooks.cpp',
124125
)
125126

126127
wrapper_deps = [

src/vulkan/wrapper/wrapper_instance.c

Lines changed: 114 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "vk_debug_utils.h"
88
#include "wrapper_debug.h"
99
#include "vk_printers.h"
10+
#include "graphics_env_hooks.h"
1011

1112
const struct vk_instance_extension_table wrapper_instance_extensions = {
1213
.KHR_get_surface_capabilities2 = true,
@@ -52,6 +53,8 @@ static struct vk_instance_extension_table *supported_instance_extensions;
5253

5354
#include <dlfcn.h>
5455

56+
static bool g_intercepted_layer_path = false;
57+
5558
static void *get_vulkan_handle_icd()
5659
{
5760
char *path = getenv("ADRENOTOOLS_DRIVER_PATH");
@@ -64,6 +67,10 @@ static void *get_vulkan_handle_icd()
6467

6568
struct stat sb;
6669

70+
if (CHECK_FLAG("USE_VVL")) {
71+
g_intercepted_layer_path = set_layer_paths();
72+
}
73+
6774
if (hooks && path && (stat(path, &sb) == 0)) {
6875
WLOG("get_vulkan_handle: hooks=%s, path=%s, name=%s", hooks, path, name);
6976
char *temp;
@@ -76,15 +83,8 @@ static void *get_vulkan_handle_icd()
7683
}
7784
}
7885

79-
// static void* icd_handle;
80-
8186
static void *get_vulkan_handle()
8287
{
83-
// __log("in get_vulkan_handle");
84-
// if (!icd_handle)
85-
// icd_handle = get_vulkan_handle_icd();
86-
// void* vvl = dlopen("/data/user/0/com.winlator.cmod/files/imagefs/usr/lib/libVkLayer_khronos_validation.so", RTLD_NOW | RTLD_LOCAL);
87-
// __log("Got vvl layer: %p", vvl);
8888
return get_vulkan_handle_icd();
8989
}
9090

@@ -298,43 +298,118 @@ WRAPPER_CreateInstance(const VkInstanceCreateInfo *pCreateInfo,
298298
wrapper_create_info.pApplicationInfo = &wrapper_application_info;
299299
wrapper_create_info.enabledExtensionCount = wrapper_enable_extension_count;
300300
wrapper_create_info.ppEnabledExtensionNames = wrapper_enable_extensions;
301+
302+
const char* layers[wrapper_create_info.enabledLayerCount + 1];
303+
char time_str[20];
304+
char path[256];
305+
const char* log_filename[] = { path };
306+
const char* report_flags[] = { "error", "info", "warn" };
307+
VkBool32 validate_sync[] = { VK_TRUE };
308+
VkBool32 printf_enable[] = { VK_TRUE };
309+
VkBool32 printf_verbose[] = { VK_TRUE };
310+
VkBool32 validate_best_practices[] = { VK_TRUE };
311+
VkBool32 validate_best_practices_arm[] = { VK_TRUE };
312+
313+
const VkLayerSettingEXT layer_setting[] = {
314+
{
315+
"VK_LAYER_KHRONOS_validation",
316+
"log_filename",
317+
VK_LAYER_SETTING_TYPE_STRING_EXT,
318+
1,
319+
log_filename,
320+
},
321+
{
322+
"VK_LAYER_KHRONOS_validation",
323+
"report_flags",
324+
VK_LAYER_SETTING_TYPE_STRING_EXT,
325+
3,
326+
report_flags,
327+
},
328+
{
329+
"VK_LAYER_KHRONOS_validation",
330+
"validate_sync",
331+
VK_LAYER_SETTING_TYPE_BOOL32_EXT,
332+
1,
333+
validate_sync,
334+
},
335+
{
336+
"VK_LAYER_KHRONOS_validation",
337+
"printf_enable",
338+
VK_LAYER_SETTING_TYPE_BOOL32_EXT,
339+
1,
340+
printf_enable,
341+
},
342+
{
343+
"VK_LAYER_KHRONOS_validation",
344+
"printf_verbose",
345+
VK_LAYER_SETTING_TYPE_BOOL32_EXT,
346+
1,
347+
printf_verbose,
348+
},
349+
{
350+
"VK_LAYER_KHRONOS_validation",
351+
"validate_best_practices",
352+
VK_LAYER_SETTING_TYPE_BOOL32_EXT,
353+
1,
354+
validate_best_practices,
355+
},
356+
{
357+
"VK_LAYER_KHRONOS_validation",
358+
"validate_best_practices_arm",
359+
VK_LAYER_SETTING_TYPE_BOOL32_EXT,
360+
1,
361+
validate_best_practices_arm,
362+
},
363+
};
364+
365+
VkLayerSettingsCreateInfoEXT layer_settings_create_info = {
366+
VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT,
367+
NULL,
368+
3,
369+
layer_setting,
370+
};
371+
372+
if (CHECK_FLAG("USE_VVL")) {
373+
if (!g_intercepted_layer_path) {
374+
WLOGE("Failed to intercept GraphicsEnv::SetLayerPaths(), cannot load VVL");
375+
return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
376+
}
377+
378+
uint32_t layerCount;
379+
_vkEnumerateInstanceLayerProperties(&layerCount, NULL);
301380

302-
// Initialize vvl
303-
// if (icd_handle != vulkan_library_handle) {
304-
// __log("Additional initialization - adding more pnext chains");
305-
// VkLayerInstanceCreateInfo *chain_info = (VkLayerInstanceCreateInfo *)&wrapper_create_info;
306-
// while ((chain_info->sType != VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO || chain_info->function != 0) && chain_info->pNext) {
307-
// chain_info = (VkLayerInstanceCreateInfo *)&chain_info->pNext;
308-
// }
309-
// if (chain_info->sType == VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO && chain_info->function == 0) {
310-
// __log("ERROR: Found a loader create info");
311-
// unreachable("");
312-
// } else {
313-
// if (!chain_info->pNext) {
314-
// __log("Starting new loader create info");
315-
// void* next = dlsym(icd_handle, "vkGetInstanceProcAddr");
316-
// __log("Next: %p", next);
317-
// VkLayerInstanceLink deviceInfo = {
318-
// .pfnNextGetInstanceProcAddr = next
319-
// };
320-
321-
// VkLayerInstanceCreateInfo info = {
322-
// .sType = VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO,
323-
// .function = 0,
324-
// .u.pLayerInfo = &deviceInfo
325-
// };
326-
// chain_info->pNext = &info;
327-
// __log("Created new loader create info");
328-
// } else {
329-
// __log("ERROR");
330-
// unreachable("");
331-
// }
332-
// }
333-
// }
381+
if (layerCount == 0) {
382+
WLOGE("No layers found, make sure that /data/data/com.winlator.cmod/files/imagefs/usr/lib/libVkLayer_khronos_validation.so exists");
383+
return vk_error(NULL, VK_ERROR_LAYER_NOT_PRESENT);
384+
} else {
385+
VkLayerProperties availableLayers[layerCount];
386+
_vkEnumerateInstanceLayerProperties(&layerCount, availableLayers);
387+
388+
WLOGD("Found %d layers in /data/data/com.winlator.cmod/files/imagefs/usr/lib/", layerCount);
389+
for (int i = 0; i < layerCount; i++) {
390+
WLOGD(" Layer[%d]: %s", i, availableLayers[i].layerName);
391+
}
392+
}
393+
394+
wrapper_create_info.enabledLayerCount += 1;
395+
for (int i = 0; i < wrapper_create_info.enabledLayerCount - 1; i++) {
396+
WLOGD("enabled_layer[%d]: %s", i, wrapper_create_info.ppEnabledLayerNames[i]);
397+
layers[i] = wrapper_create_info.ppEnabledLayerNames[i];
398+
}
399+
layers[wrapper_create_info.enabledLayerCount - 1] = "VK_LAYER_KHRONOS_validation";
400+
wrapper_create_info.ppEnabledLayerNames = layers;
401+
402+
get_current_time_string(time_str, sizeof(time_str));
403+
sprintf(path, "/sdcard/Documents/Wrapper/%s_%s.%s.%d.txt", "vvl", time_str, getprogname(), getpid());
404+
layer_settings_create_info.pNext = wrapper_create_info.pNext;
405+
wrapper_create_info.pNext = &layer_settings_create_info;
406+
}
334407

335408
result = dispatch_create_instance(&wrapper_create_info, pAllocator,
336409
&instance->dispatch_handle);
410+
337411
if (result != VK_SUCCESS) {
412+
WLOGE("vkCreateInstance failed, result = %d", result);
338413
vk_instance_finish(&instance->vk);
339414
vk_free2(vk_default_allocator(), pAllocator, instance);
340415
return vk_error(NULL, result);

src/vulkan/wrapper/wrapper_private.h

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -163,62 +163,6 @@ static inline uint32_t get_bc_block_size(VkFormat format) {
163163
}
164164
}
165165

166-
167-
typedef enum VkLayerFunction_ {
168-
VK_LAYER_FUNCTION_LINK = 0,
169-
VK_LAYER_FUNCTION_DEVICE = 1,
170-
VK_LAYER_FUNCTION_INSTANCE = 2
171-
} VkLayerFunction;
172-
/*
173-
* When creating the device chain the loader needs to pass
174-
* down information about it's device structure needed at
175-
* the end of the chain. Passing the data via the
176-
* VkLayerInstanceInfo avoids issues with finding the
177-
* exact instance being used.
178-
*/
179-
typedef struct VkLayerInstanceInfo_ {
180-
void* instance_info;
181-
PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
182-
} VkLayerInstanceInfo;
183-
typedef struct VkLayerInstanceLink_ {
184-
struct VkLayerInstanceLink_* pNext;
185-
PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
186-
} VkLayerInstanceLink;
187-
/*
188-
* When creating the device chain the loader needs to pass
189-
* down information about it's device structure needed at
190-
* the end of the chain. Passing the data via the
191-
* VkLayerDeviceInfo avoids issues with finding the
192-
* exact instance being used.
193-
*/
194-
typedef struct VkLayerDeviceInfo_ {
195-
void* device_info;
196-
PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
197-
} VkLayerDeviceInfo;
198-
typedef struct {
199-
VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO
200-
const void* pNext;
201-
VkLayerFunction function;
202-
union {
203-
VkLayerInstanceLink* pLayerInfo;
204-
VkLayerInstanceInfo instanceInfo;
205-
} u;
206-
} VkLayerInstanceCreateInfo;
207-
typedef struct VkLayerDeviceLink_ {
208-
struct VkLayerDeviceLink_* pNext;
209-
PFN_vkGetInstanceProcAddr pfnNextGetInstanceProcAddr;
210-
PFN_vkGetDeviceProcAddr pfnNextGetDeviceProcAddr;
211-
} VkLayerDeviceLink;
212-
typedef struct {
213-
VkStructureType sType; // VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO
214-
const void* pNext;
215-
VkLayerFunction function;
216-
union {
217-
VkLayerDeviceLink* pLayerInfo;
218-
VkLayerDeviceInfo deviceInfo;
219-
} u;
220-
} VkLayerDeviceCreateInfo;
221-
222166
static VkFormat unwrap_vk_format_physical_device(struct wrapper_physical_device* pdevice, VkFormat in_format) {
223167
if (!pdevice) {
224168
WLOGE("unwrap_vk_format: null pdevice");

0 commit comments

Comments
 (0)