mirror of
https://github.com/Ed94/raddebugger.git
synced 2026-08-14 17:28:07 +00:00
implement /INFERASANLIBS
This commit is contained in:
+93
-8
@@ -1350,7 +1350,7 @@ lnk_load_inputs(TP_Context *tp, TP_Arena *arena, LNK_Config *config, LNK_Inputer
|
||||
AssertAlways(include_obj_count == 1);
|
||||
|
||||
if (obj_with_includes) {
|
||||
DLLInsert(link->objs.first, link->objs.last, obj_with_includes->node, include_obj);
|
||||
DLLInsert(link->objs.first, link->objs.last, obj_with_includes->self, include_obj);
|
||||
link->objs.count += 1;
|
||||
} else {
|
||||
lnk_obj_list_push_node(&link->objs, include_obj);
|
||||
@@ -1579,6 +1579,40 @@ THREAD_POOL_TASK_FUNC(lnk_search_lib_task)
|
||||
}
|
||||
}
|
||||
|
||||
internal LNK_Lib *
|
||||
lnk_find_first_crt_lib(LNK_Config *config, LNK_Inputer *inputer)
|
||||
{
|
||||
Temp scratch = scratch_begin(0, 0);
|
||||
|
||||
LNK_Lib *result = 0;
|
||||
|
||||
String8 crt_lib_names[] = {
|
||||
str8_lit("msvcrt"),
|
||||
str8_lit("msvcrtd"),
|
||||
str8_lit("libcmt"),
|
||||
str8_lit("libcmtd"),
|
||||
};
|
||||
|
||||
for EachNode(n, LNK_Input, inputer->libs.first) {
|
||||
String8 lib_name = str8_chop_last_dot(str8_skip_last_slash(n->path));
|
||||
for EachElement(i, crt_lib_names) {
|
||||
if (str8_match(lib_name, crt_lib_names[i], StringMatchFlag_CaseInsensitive)) {
|
||||
if (result == 0) {
|
||||
result = hash_table_search_path_raw(inputer->libs_ht, n->path);
|
||||
break;
|
||||
} else {
|
||||
LNK_Lib *lib = hash_table_search_path_raw(inputer->libs_ht, n->path);
|
||||
result = lib->input_idx < result->input_idx ? lib : result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scratch_end(scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_link_inputs(TP_Context *tp,
|
||||
TP_Arena *arena,
|
||||
@@ -1598,6 +1632,57 @@ lnk_link_inputs(TP_Context *tp,
|
||||
for EachNode(lib_n, LNK_LibNode, link->libs.first) {
|
||||
LNK_Lib *lib = &lib_n->data;
|
||||
|
||||
if (config->machine != COFF_MachineType_Unknown) {
|
||||
if (config->infer_asan_libs == LNK_SwitchState_Yes) {
|
||||
if ( ! link->asan_libs_resolved) {
|
||||
LNK_Lib *crt_lib = lnk_find_first_crt_lib(config, inputer);
|
||||
if (crt_lib != 0) {
|
||||
String8 crt_lib_name = str8_chop_last_dot(str8_skip_last_slash(crt_lib->path));
|
||||
|
||||
String8 arch_name = {0};
|
||||
if (config->machine == COFF_MachineType_X64) {
|
||||
arch_name = str8_lit("x86_64");
|
||||
} else if (config->machine == COFF_MachineType_X86) {
|
||||
arch_name = str8_lit("i386");
|
||||
}
|
||||
|
||||
if (arch_name.size) {
|
||||
B32 link_vc_libs = lnk_symbol_table_searchf(symtab, "__you_must_link_with_VCAsan_lib") != 0 ||
|
||||
lnk_symbol_table_searchf(symtab, "___you_must_link_with_VCAsan_lib") != 0;
|
||||
if (str8_match(crt_lib_name, str8_lit("msvcrt"), StringMatchFlag_CaseInsensitive) || str8_match(crt_lib_name, str8_lit("msvcrtd"), StringMatchFlag_CaseInsensitive)) {
|
||||
String8 dynamic_lib_name = str8f(inputer->arena, "clang_rt.asan_dynamic-%S.lib", arch_name);
|
||||
String8 thunk_lib_name = str8f(inputer->arena, "clang_rt.asan_static_runtime_thunk-%S.lib", arch_name);
|
||||
lnk_whole_archive(config, thunk_lib_name);
|
||||
lnk_inputer_push_lib_thin(inputer, config, LNK_InputSource_Obj, dynamic_lib_name);
|
||||
lnk_inputer_push_lib_thin(inputer, config, LNK_InputSource_Obj, thunk_lib_name);
|
||||
if (link_vc_libs) {
|
||||
if (str8_match(crt_lib_name, str8_lit("msvcrtd"), StringMatchFlag_CaseInsensitive)) {
|
||||
lnk_inputer_push_lib_thin(inputer, config, LNK_InputSource_Obj, str8_lit("libvcasand.lib"));
|
||||
} else {
|
||||
lnk_inputer_push_lib_thin(inputer, config, LNK_InputSource_Obj, str8_lit("libvcasan.lib"));
|
||||
}
|
||||
}
|
||||
} else if (str8_match(crt_lib_name, str8_lit("libcmt"), StringMatchFlag_CaseInsensitive) || str8_match(crt_lib_name, str8_lit("libcmtd"), StringMatchFlag_CaseInsensitive)) {
|
||||
String8 dynamic_lib_name = str8f(inputer->arena, "clang_rt.asan_dynamic-%S.lib", arch_name);
|
||||
String8 thunk_lib_name = str8f(inputer->arena, "clang_rt.asan_dynamic_runtime_thunk-%S.lib", arch_name);
|
||||
lnk_whole_archive(config, thunk_lib_name);
|
||||
lnk_inputer_push_lib_thin(inputer, config, LNK_InputSource_Obj, dynamic_lib_name);
|
||||
lnk_inputer_push_lib_thin(inputer, config, LNK_InputSource_Obj, thunk_lib_name);
|
||||
if (link_vc_libs) {
|
||||
if (str8_match(crt_lib_name, str8_lit("libcmtd"), StringMatchFlag_CaseInsensitive)) {
|
||||
lnk_inputer_push_lib_thin(inputer, config, LNK_InputSource_Obj, str8_lit("vcasand.lib"));
|
||||
} else {
|
||||
lnk_inputer_push_lib_thin(inputer, config, LNK_InputSource_Obj, str8_lit("vcasan.lib"));
|
||||
}
|
||||
}
|
||||
}
|
||||
link->asan_libs_resolved = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LNK_LibMemberInfo *lib_member_infos = hash_table_search_raw_raw(link->lib_member_infos_ht, lib);
|
||||
if (lib_member_infos == 0) {
|
||||
lib_member_infos = push_array(link->arena, LNK_LibMemberInfo, lib->member_count);
|
||||
@@ -1615,15 +1700,15 @@ lnk_link_inputs(TP_Context *tp,
|
||||
lnk_load_inputs(tp, arena, config, inputer, symtab, link);
|
||||
|
||||
if (link_whole_archive) {
|
||||
local_persist LNK_Symbol *null_symbol = 0;
|
||||
if (null_symbol == 0) {
|
||||
null_symbol = push_array(inputer->arena, LNK_Symbol, 1);
|
||||
null_symbol->refs = push_array(inputer->arena, LNK_ObjSymbolRefNode, 1);
|
||||
null_symbol->refs->v.obj = &link->objs.first->data;
|
||||
}
|
||||
LNK_LibMemberRef *member_refs = push_array(scratch.arena, LNK_LibMemberRef, lib->member_count);
|
||||
for EachIndex(member_idx, lib->member_count) {
|
||||
static LNK_Symbol *null_symbol = 0;
|
||||
if (null_symbol == 0) {
|
||||
null_symbol = push_array(inputer->arena, LNK_Symbol, 1);
|
||||
null_symbol->refs = push_array(inputer->arena, LNK_ObjSymbolRefNode, 1);
|
||||
null_symbol->refs->v.obj = &link->objs.first->data;
|
||||
}
|
||||
lnk_queue_lib_member(scratch.arena, &member_ref_lists[0], null_symbol, lib, lib_member_infos, member_idx);
|
||||
lnk_queue_lib_member(arena->v[0], &member_ref_lists[0], null_symbol, lib, lib_member_infos, member_idx);
|
||||
}
|
||||
} else {
|
||||
// search symbols in lib
|
||||
|
||||
+1
-1
@@ -37,7 +37,6 @@ typedef struct LNK_Input
|
||||
B32 has_disk_read_failed;
|
||||
B32 exclude_from_debug_info;
|
||||
LNK_LibMemberRef *link_member;
|
||||
void *loaded_input;
|
||||
|
||||
struct LNK_Input *next;
|
||||
} LNK_Input;
|
||||
@@ -104,6 +103,7 @@ typedef struct LNK_Link
|
||||
HashTable *lib_member_infos_ht;
|
||||
LNK_LibMemberRefList imports;
|
||||
B32 try_to_resolve_entry_point;
|
||||
B32 asan_libs_resolved;
|
||||
} LNK_Link;
|
||||
|
||||
typedef struct LNK_LinkResult
|
||||
|
||||
@@ -974,6 +974,15 @@ lnk_include_symbol(LNK_Config *config, String8 name, LNK_Obj *obj)
|
||||
hash_table_push_string_raw(config->arena, config->include_symbol_ht, name, node);
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_whole_archive(LNK_Config *config, String8 lib_name)
|
||||
{
|
||||
String8Node value = { .string = lib_name };
|
||||
String8List value_strings = {0};
|
||||
str8_list_push_node(&value_strings, &value);
|
||||
lnk_apply_cmd_option_to_config(config, str8_lit("wholearchive"), value_strings, 0);
|
||||
}
|
||||
|
||||
internal void
|
||||
lnk_print_build_info()
|
||||
{
|
||||
@@ -1443,6 +1452,10 @@ lnk_apply_cmd_option_to_config(LNK_Config *config, String8 cmd_name, String8List
|
||||
}
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_InferAsanLibs: {
|
||||
lnk_cmd_switch_parse_flag(obj, cmd_switch, value_strings, &config->infer_asan_libs);
|
||||
} break;
|
||||
|
||||
case LNK_CmdSwitch_LargeAddressAware: {
|
||||
lnk_cmd_switch_set_flag_16(obj, cmd_switch, value_strings, &config->file_characteristics, PE_ImageFileCharacteristic_LARGE_ADDRESS_AWARE);
|
||||
} break;
|
||||
|
||||
@@ -293,6 +293,7 @@ typedef struct LNK_Config
|
||||
U64 function_pad_min;
|
||||
U64 *manifest_resource_id;
|
||||
B32 no_default_libs;
|
||||
LNK_SwitchState infer_asan_libs;
|
||||
Version link_ver;
|
||||
Version os_ver;
|
||||
Version image_ver;
|
||||
@@ -550,6 +551,8 @@ internal B32 lnk_is_lib_disallowed(LNK_Config *config, String8 path);
|
||||
|
||||
internal void lnk_include_symbol(LNK_Config *config, String8 name, struct LNK_Obj *obj);
|
||||
|
||||
internal void lnk_whole_archive(LNK_Config *config, String8 lib_name);
|
||||
|
||||
// --- Config ------------------------------------------------------------------
|
||||
|
||||
internal void lnk_apply_cmd_option_to_config(LNK_Config *config, String8 name, String8List value_list, struct LNK_Obj *obj);
|
||||
|
||||
@@ -107,6 +107,7 @@ typedef enum
|
||||
LNK_Warning_DirectiveSectionWithRelocs,
|
||||
LNK_Warning_NoLargeAddressAwarenessForDll,
|
||||
LNK_Warning_TryingToExportEntryPoint,
|
||||
LNK_Warning_InferAsanFail,
|
||||
LNK_Warning_Last,
|
||||
|
||||
LNK_Error_Count
|
||||
|
||||
@@ -336,7 +336,7 @@ THREAD_POOL_TASK_FUNC(lnk_obj_initer)
|
||||
obj->exclude_from_debug_info = input->exclude_from_debug_info;
|
||||
obj->hotpatch = hotpatch;
|
||||
obj->associated_sections = associated_sections;
|
||||
obj->node = &task->objs[task_id];
|
||||
obj->self = &task->objs[task_id];
|
||||
obj->link_member = input->link_member;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,8 @@ typedef struct LNK_Obj
|
||||
B8 exclude_from_debug_info;
|
||||
U32Node **associated_sections;
|
||||
LNK_SymbolHashTrie **symlinks;
|
||||
|
||||
struct LNK_LibMemberRef *link_member;
|
||||
|
||||
struct LNK_ObjNode *node;
|
||||
struct LNK_ObjNode *self;
|
||||
} LNK_Obj;
|
||||
|
||||
typedef struct LNK_ObjNode
|
||||
|
||||
@@ -119,6 +119,24 @@ t_radbin_path(void)
|
||||
return path;
|
||||
}
|
||||
|
||||
internal String8
|
||||
t_cl_path(void)
|
||||
{
|
||||
local_persist String8 path = {0};
|
||||
if (path.size == 0) {
|
||||
local_persist U8 buffer[4096];
|
||||
ArenaParams params = { .reserve_size = sizeof(buffer), .commit_size = sizeof(buffer), .optional_backing_buffer = buffer };
|
||||
Arena *arena = arena_alloc_(¶ms);
|
||||
#if OS_WINDOWS
|
||||
path = str8_lit("cl.exe");
|
||||
#else
|
||||
path = str8_lit("cl");
|
||||
#endif
|
||||
AssertAlways(path.size);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
internal String8
|
||||
t_radlink_path(void)
|
||||
{
|
||||
|
||||
@@ -91,6 +91,10 @@ internal void t_run_caller(void *raw_ctx);
|
||||
internal void t_run_fail_handler(void *raw_ctx);
|
||||
internal T_RunResult t_run(T_Run run);
|
||||
|
||||
internal String8 t_radbin_path(void);
|
||||
internal String8 t_cl_path(void);
|
||||
internal String8 t_radlink_path(void);
|
||||
|
||||
internal B32 t_invoke(String8 exe, String8 cmdline, U64 timeout);
|
||||
|
||||
|
||||
|
||||
@@ -4837,19 +4837,111 @@ T_BeginTest(whole_archive)
|
||||
}
|
||||
T_EndTest;
|
||||
|
||||
#if OS_WINDOWS
|
||||
|
||||
internal B32
|
||||
t_radlink_validate_asan_out(String8 obj_name)
|
||||
{
|
||||
Temp scratch = scratch_begin(0,0);
|
||||
B32 is_ok = 0;
|
||||
|
||||
t_invoke_(t_radlink_path(), str8f(scratch.arena, "%S /debug:full", obj_name), max_U64, 0, 0);
|
||||
if (g_last_exit_code != 0) { goto exit; }
|
||||
|
||||
String8 exe_path = t_make_file_path(scratch.arena, str8f(scratch.arena, "%S.exe", str8_chop_last_dot(obj_name)));
|
||||
String8 out = {0};
|
||||
t_invoke_(exe_path, str8_zero(), max_U64, scratch.arena, &out);
|
||||
if (g_last_exit_code == 0) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
String8 s = out;
|
||||
|
||||
String8 header = t_chop_line(&s);
|
||||
if ( ! str8_match(header, str8_lit("================================================================="), 0)) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
String8 cause = t_chop_line(&s);
|
||||
if ( str8_find_needle(cause, 0, str8_lit("AddressSanitizer: heap-use-after-free on address"), 0) >= cause.size) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
is_ok = 1;
|
||||
exit:;
|
||||
scratch_end(scratch);
|
||||
return is_ok;
|
||||
}
|
||||
|
||||
T_BeginTest(infer_asan)
|
||||
{
|
||||
char *program =
|
||||
"#include <stdlib.h>\n"
|
||||
" int main(void) {\n"
|
||||
"int *foo = malloc(sizeof(*foo));\n"
|
||||
"free(foo);\n"
|
||||
"*foo = 1;\n"
|
||||
"}\n"
|
||||
;
|
||||
|
||||
// /MD
|
||||
{
|
||||
T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program)));
|
||||
String8 cl_output = {0};
|
||||
t_invoke_(t_cl_path(), str8_lit("/MD /fsanitize=address /Z7 /c /Fo:main_md.obj main.c"), max_U64, scratch.arena, &cl_output);
|
||||
T_Ok(g_last_exit_code == 0);
|
||||
T_Ok(t_radlink_validate_asan_out(str8_lit("main_md.obj")));
|
||||
}
|
||||
|
||||
// /MDd
|
||||
{
|
||||
T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program)));
|
||||
String8 cl_output = {0};
|
||||
t_invoke_(t_cl_path(), str8_lit("/MDd /fsanitize=address /Z7 /c /Fo:main_mdd.obj main.c"), max_U64, scratch.arena, &cl_output);
|
||||
T_Ok(g_last_exit_code == 0);
|
||||
T_Ok(t_radlink_validate_asan_out(str8_lit("main_mdd.obj")));
|
||||
}
|
||||
|
||||
// /MT
|
||||
{
|
||||
T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program)));
|
||||
String8 cl_output = {0};
|
||||
t_invoke_(t_cl_path(), str8_lit("/MT /fsanitize=address /Z7 /c /Fo:main_mt.obj main.c"), max_U64, scratch.arena, &cl_output);
|
||||
T_Ok(g_last_exit_code == 0);
|
||||
T_Ok(t_radlink_validate_asan_out(str8_lit("main_mt.obj")));
|
||||
}
|
||||
|
||||
// /MTd
|
||||
{
|
||||
T_Ok(t_write_file(str8_lit("main.c"), str8_cstring(program)));
|
||||
String8 cl_output = {0};
|
||||
t_invoke_(t_cl_path(), str8_lit("/MT /fsanitize=address /Z7 /c /Fo:main_mtd.obj main.c"), max_U64, scratch.arena, &cl_output);
|
||||
T_Ok(g_last_exit_code == 0);
|
||||
T_Ok(t_radlink_validate_asan_out(str8_lit("main_mtd.obj")));
|
||||
}
|
||||
}
|
||||
T_EndTest;
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
T_BeginTest(pdb_determ_test)
|
||||
T_BeginTest(determ_test)
|
||||
{
|
||||
T_Ok(os_copy_file_path(t_make_file_path(scratch.arena, str8_lit("torture_main.obj")), str8_lit("torture_main.obj")));
|
||||
|
||||
t_delete_file(str8_lit("a.exe"));
|
||||
t_delete_file(str8_lit("b.exe"));
|
||||
t_delete_file(str8_lit("a.pdb"));
|
||||
t_delete_file(str8_lit("b.pdb"));
|
||||
|
||||
String8 refs_path = t_make_file_path(scratch.arena, str8_lit("b.types"));
|
||||
t_invoke_linkerf("torture_main.obj /debug:full /rad_time_stamp:0 /rad_workers:1 /rad_store_types:%S /out:a.exe", refs_path);
|
||||
T_Ok(g_last_exit_code == 0);
|
||||
|
||||
T_Ok(os_move_file_path(t_make_file_path(scratch.arena, str8_lit("b.exe")), t_make_file_path(scratch.arena, str8_lit("a.exe"))));
|
||||
T_Ok(os_move_file_path(t_make_file_path(scratch.arena, str8_lit("b.pdb")), t_make_file_path(scratch.arena, str8_lit("a.pdb"))));
|
||||
String8 b = t_read_file(scratch.arena, str8_lit("b.pdb"));
|
||||
|
||||
String8 b_exe = t_read_file(scratch.arena, str8_lit("b.exe"));
|
||||
String8 b_pdb = t_read_file(scratch.arena, str8_lit("b.pdb"));
|
||||
|
||||
for EachIndex(i, 50) {
|
||||
Temp temp = temp_begin(scratch.arena);
|
||||
@@ -4858,8 +4950,10 @@ T_BeginTest(pdb_determ_test)
|
||||
t_invoke_linkerf("torture_main.obj /debug:full /rad_time_stamp:0 /out:a.exe");
|
||||
T_Ok(g_last_exit_code == 0);
|
||||
|
||||
String8 a = t_read_file(temp.arena, str8_lit("a.pdb"));
|
||||
T_Ok(str8_match(a, b, 0));
|
||||
String8 a_exe = t_read_file(temp.arena, str8_lit("a.exe"));
|
||||
String8 a_pdb = t_read_file(temp.arena, str8_lit("a.pdb"));
|
||||
T_Ok(str8_match(a_exe, b_exe, 0));
|
||||
T_Ok(str8_match(a_pdb, b_pdb, 0));
|
||||
|
||||
temp_end(temp);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user