Native Linux backtrace.

This commit is contained in:
Christoffer Lerno
2023-11-11 14:16:36 +01:00
committed by Christoffer Lerno
parent f39aa1a41e
commit dc0aa35522
15 changed files with 343 additions and 110 deletions

View File

@@ -264,6 +264,7 @@ jobs:
../build/c3c compile-run examples/load_world.c3
../build/c3c compile-run examples/process.c3
../build/c3c compile-run examples/ls.c3
../build/c3c compile-run linux_stack.c3
- name: Compile run unit tests
run: |

View File

@@ -87,11 +87,11 @@ struct CallstackElement
uint line;
}
fn bool print_backtrace(String message, int backtraces_to_ignore) @if(env::DARWIN)
fn bool print_backtrace(String message, int backtraces_to_ignore) @if(env::DARWIN || env::LINUX)
{
@pool()
{
BacktraceList! backtrace = darwin::backtrace_load(mem::temp());
BacktraceList! backtrace = backtrace::backtrace_load(mem::temp());
if (catch backtrace) return false;
if (backtrace.len() <= backtraces_to_ignore) return false;
io::eprint("\nERROR: '");

View File

@@ -50,6 +50,9 @@ fn void Backtrace.free(&self)
self.allocator.free(self.file);
}
def backtrace_load = darwin::backtrace_load @if(env::DARWIN);
def backtrace_load = linux::backtrace_load @if(env::LINUX);
fn Backtrace* Backtrace.init(&self, uptr offset, String function, String object_file, String file = "", uint line = 0, Allocator* using = mem::heap())
{
if (!using)

199
lib/std/os/linux/linux.c3 Normal file
View File

@@ -0,0 +1,199 @@
module std::os::linux @if(env::LINUX);
import libc;
import std::os::posix;
import std::io;
import std::collections::list;
extern fn isz readlink(ZString path, char* buf, usz bufsize);
def BacktraceList = List(<Backtrace>);
const PT_PHDR = 6;
const EI_NIDENT = 16;
def Elf32_Half = ushort;
def Elf32_Word = uint;
def Elf32_Addr = uint;
def Elf32_Off = uint;
struct Elf32_Ehdr
{
char[EI_NIDENT] e_ident;
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry;
Elf32_Off e_phoff;
Elf32_Off e_shoff;
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
}
struct Elf32_Phdr
{
Elf32_Word p_type;
Elf32_Off p_offset;
Elf32_Addr p_vaddr;
Elf32_Addr p_paddr;
Elf32_Word p_filesz;
Elf32_Word p_memsz;
Elf32_Word p_flags;
Elf32_Word p_align;
}
def Elf64_Addr = ulong;
def Elf64_Half = ushort;
def Elf64_Off = ulong;
def Elf64_Word = uint;
def Elf64_Sword = int;
def Elf64_Sxword = long;
def Elf64_Lword = ulong;
def Elf64_Xword = ulong;
struct Elf64_Ehdr
{
char[EI_NIDENT] e_ident;
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
Elf64_Addr e_entry;
Elf64_Off e_phoff;
Elf64_Off e_shoff;
Elf64_Word e_flags;
Elf64_Half e_ehsize;
Elf64_Half e_phentsize;
Elf64_Half e_phnum;
Elf64_Half e_shentsize;
Elf64_Half e_shnum;
Elf64_Half e_shstrndx;
}
struct Elf64_Phdr
{
Elf64_Word p_type;
Elf64_Word p_flags;
Elf64_Off p_offset;
Elf64_Addr p_vaddr;
Elf64_Addr p_paddr;
Elf64_Xword p_filesz;
Elf64_Xword p_memsz;
Elf64_Xword p_align;
}
extern fn CInt dladdr(void* addr, Linux_Dl_info* info);
struct Linux_Dl_info
{
ZString dli_fname; /* Pathname of shared object */
void* dli_fbase; /* Base address of shared object */
ZString dli_sname; /* Name of nearest symbol */
void* dli_saddr; /* Address of nearest symbol */
}
fn ulong! elf_module_image_base(String path) @local
{
File file = file::open(path, "rb")!;
defer (void)file.close();
char[4] buffer;
io::read_all(&file, &buffer)!;
if (buffer != char[4]{ 0x7f, 'E', 'L', 'F'}) return BacktraceFault.IMAGE_NOT_FOUND?;
bool is_64 = file.read_byte()! == 2;
bool is_little_endian = file.read_byte()! == 1;
// Actually, not supported.
if (!is_little_endian) return BacktraceFault.IMAGE_NOT_FOUND?;
file.seek(0)!;
if (is_64)
{
Elf64_Ehdr file_header;
io::read_any(&file, &file_header)!;
if (file_header.e_ehsize != Elf64_Ehdr.sizeof) return BacktraceFault.IMAGE_NOT_FOUND?;
for (isz i = 0; i < file_header.e_phnum; i++)
{
Elf64_Phdr header;
file.seek((usz)file_header.e_phoff + (usz)file_header.e_phentsize * i)!;
io::read_any(&file, &header)!;
if (header.p_type == PT_PHDR) return header.p_vaddr - header.p_offset;
}
return 0;
}
Elf32_Ehdr file_header;
io::read_any(&file, &file_header)!;
if (file_header.e_ehsize != Elf32_Ehdr.sizeof) return BacktraceFault.IMAGE_NOT_FOUND?;
for (isz i = 0; i < file_header.e_phnum; i++)
{
Elf32_Phdr header;
file.seek(file_header.e_phoff + (usz)file_header.e_phentsize * i)!;
io::read_any(&file, &header)!;
if (header.p_type == PT_PHDR) return (ulong)header.p_vaddr - header.p_offset;
}
return 0;
}
fn Backtrace! backtrace_load_element(void* addr, Allocator* allocator = mem::heap()) @local
{
@pool(allocator)
{
if (!addr) return backtrace::BACKTRACE_UNKNOWN;
char[] buf = mem::temp_array(char, 1024);
Linux_Dl_info info;
if (dladdr(addr, &info) == 0) return backtrace::BACKTRACE_UNKNOWN;
void* obj_address = addr - (uptr)info.dli_fbase + (uptr)elf_module_image_base(info.dli_fname.str_view())!;
ZString obj_path = info.dli_fname;
String s = process::execute_stdout_to_buffer(buf, { "addr2line", "-p", "-i", "-C", "-f", "-e", obj_path.str_view(), string::tformat("0x%x", obj_address) })!;
String[] parts = s.tsplit(" at ");
if (parts.len != 2)
{
return {
.function = info.dli_sname ? info.dli_sname.copy(allocator) : "???".copy(allocator),
.object_file = info.dli_fname.copy(allocator),
.offset = (uptr)addr,
.file = "".copy(allocator),
.line = 0
};
}
uint line = 0;
String source = "";
if (!parts[1].contains("?") && parts[1].contains(":"))
{
usz index = parts[1].rindex_of_char(':')!;
source = parts[1][:index];
line = parts[1][index + 1..].to_uint()!;
}
return {
.function = parts[0].copy(allocator),
.object_file = info.dli_fname.copy(allocator),
.file = source.copy(allocator),
.line = line,
.allocator = allocator
};
};
}
fn BacktraceList! backtrace_load(Allocator* allocator)
{
void*[256] bt_buffer;
CInt size = posix::backtrace(&bt_buffer, 256);
BacktraceList list;
list.init_new(size, allocator);
defer catch
{
foreach (trace : list)
{
trace.free();
}
list.free();
}
@pool(allocator)
{
for (usz i = 1; i < size; i++)
{
Backtrace trace = backtrace_load_element(bt_buffer[i], allocator)!;
list.append(trace);
}
};
return list;
}

View File

@@ -101,15 +101,12 @@ fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_a
{
if (buffer)
{
SubProcess process = process::create({ "atos",
"-o", execpath, "-arch", env::AARCH64 ? "arm64" : "x86_64", "-l",
char* buf = tmalloc(1024);
String s = process::execute_stdout_to_buffer(buf[:1024],
{ "atos", "-o", execpath, "-arch", env::AARCH64 ? "arm64" : "x86_64", "-l",
string::tformat("%p", load_address),
string::tformat("%p", buffer),
"-fullPath" })!;
process.join()!;
char* buf = tmalloc(1024);
usz len = process.read_stdout(buf, 1024)!;
String s = (String)buf[:len - 1];
String[] parts = s.tsplit(" ");
if (parts.len == 4)
{

View File

@@ -269,6 +269,13 @@ fn ZString* tcopy_env(String[] environment) @local @inline @if(env::POSIX)
return copy;
}
fn String! execute_stdout_to_buffer(char[] buffer, String[] command_line, SubProcessOptions options = {}, String[] environment = {})
{
SubProcess process = process::create(command_line, options, environment)!;
process.join()!;
usz len = process.read_stdout(buffer.ptr, buffer.len)!;
return (String)buffer[:len - 1];
}
/**
* @require !environment || !options.inherit_environment

10
resources/linux_stack.c3 Normal file
View File

@@ -0,0 +1,10 @@
module test;
import std::io;
import std::collections::map;
import std::os;
fn void! main()
{
int x = 2;
builtin::print_backtrace("Hello", 0);
}

View File

@@ -2367,6 +2367,7 @@ void codegen_setup_object_names(Module *module, const char **ir_filename, const
void target_setup(BuildTarget *build_target);
int target_alloca_addr_space();
bool os_is_apple(OsType os_type);
bool os_supports_stacktrace(OsType os_type);
bool arch_is_wasm(ArchType type);
const char *macos_sysroot(void);

View File

@@ -386,9 +386,17 @@ static void linker_setup_linux(const char ***args_ref, LinkerType linker_type)
{
if (linker_type == LINKER_CC)
{
if (active_target.debug_info == DEBUG_INFO_FULL)
{
add_arg("-rdynamic");
}
add_arg("-pthread");
return;
}
if (active_target.debug_info == DEBUG_INFO_FULL)
{
add_arg("-export-dynamic");
}
if (is_no_pie(platform_target.reloc_model)) add_arg("-no-pie");
if (is_pie(platform_target.reloc_model)) add_arg("-pie");
if (platform_target.arch == ARCH_TYPE_X86_64) add_arg("--eh-frame-hdr");

View File

@@ -152,6 +152,7 @@ void gencontext_begin_module(GenContext *c)
{
llvm_set_module_flag(c, LLVMModuleFlagBehaviorWarning, "Dwarf Version", 4, type_uint);
llvm_set_module_flag(c, LLVMModuleFlagBehaviorWarning, "Debug Info Version", 3, type_uint);
llvm_set_module_flag(c, LLVMModuleFlagBehaviorWarning, "frame-pointer", 2, type_uint);
}
llvm_set_module_flag(c, LLVMModuleFlagBehaviorError, "uwtable", 2, type_uint);
@@ -168,7 +169,7 @@ void gencontext_begin_module(GenContext *c)
LLVMStructSetBody(c->debug.stack_type, types, 5, false);
c->debug.current_stack_ptr = NULL;
c->debug.enable_stacktrace = true;
c->debug.emulated_stacktrace = !os_is_apple(platform_target.os);
c->debug.emulated_stacktrace = !os_supports_stacktrace(platform_target.os);
}
}
c->global_builder = LLVMCreateBuilder();

View File

@@ -32,6 +32,10 @@ int target_alloca_addr_space()
return platform_target.alloca_address_space;
}
bool os_supports_stacktrace(OsType os_type)
{
return os_type == OS_TYPE_LINUX || os_is_apple(os_type);
}
bool os_is_apple(OsType os_type)
{
return os_type == OS_TYPE_TVOS || os_type == OS_TYPE_WATCHOS ||

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.4.699"
#define COMPILER_VERSION "0.4.700"

View File

@@ -22,43 +22,44 @@ fn void main()
/* #expect: test.ll
%.introspect = type { i8, i64, ptr, i64, i64, i64, [0 x i64] }
%"any*" = type { ptr, i64 }
@"$ct.test.Ghh" = linkonce global %.introspect { i8 10, i64 0, ptr null, i64 12, i64 0, i64 3, [0 x i64] zeroinitializer }, align 8
@.str = private unnamed_addr constant [3 x i8] c"%d\00", align 1
@"$ct.int" = linkonce global %.introspect { i8 2, i64 0, ptr null, i64 4, i64 0, i64 0, [0 x i64] zeroinitializer }, align 8
define void @test.main() #0 !dbg !5 {
define void @test.main() #0 !dbg !6 {
entry:
%a = alloca i32, align 4
%x = alloca i32, align 4
%y = alloca i32, align 4
%varargslots = alloca [1 x %"any*"], align 16
%retparam = alloca i64, align 8
call void @llvm.dbg.declare(metadata ptr %a, metadata !9, metadata !DIExpression()), !dbg !11
store i32 111, ptr %a, align 4, !dbg !12
call void @llvm.dbg.declare(metadata ptr %x, metadata !13, metadata !DIExpression()), !dbg !14
%0 = load atomic i32, ptr %a seq_cst, align 4, !dbg !15
store i32 %0, ptr %x, align 4, !dbg !15
call void @llvm.dbg.declare(metadata ptr %y, metadata !18, metadata !DIExpression()), !dbg !19
%1 = load atomic volatile i32, ptr %a monotonic, align 4, !dbg !20
store i32 %1, ptr %y, align 4, !dbg !20
%2 = load i32, ptr %x, align 4, !dbg !22
%add = add i32 123, %2, !dbg !23
store atomic i32 %add, ptr %a seq_cst, align 4, !dbg !24
%3 = load i32, ptr %y, align 4, !dbg !26
%add1 = add i32 33, %3, !dbg !27
store atomic volatile i32 %add1, ptr %a monotonic, align 4, !dbg !28
%4 = insertvalue %"any*" undef, ptr %a, 0, !dbg !30
%5 = insertvalue %"any*" %4, i64 ptrtoint (ptr @"$ct.int" to i64), 1, !dbg !30
%6 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0, !dbg !30
store %"any*" %5, ptr %6, align 16, !dbg !30
%7 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 2, ptr %varargslots, i64 1), !dbg !31
ret void, !dbg !31
call void @llvm.dbg.declare(metadata ptr %a, metadata !10, metadata !DIExpression()), !dbg !12
store i32 111, ptr %a, align 4, !dbg !13
call void @llvm.dbg.declare(metadata ptr %x, metadata !14, metadata !DIExpression()), !dbg !15
%0 = load atomic i32, ptr %a seq_cst, align 4, !dbg !16
store i32 %0, ptr %x, align 4, !dbg !16
call void @llvm.dbg.declare(metadata ptr %y, metadata !19, metadata !DIExpression()), !dbg !20
%1 = load atomic volatile i32, ptr %a monotonic, align 4, !dbg !21
store i32 %1, ptr %y, align 4, !dbg !21
%2 = load i32, ptr %x, align 4, !dbg !23
%add = add i32 123, %2, !dbg !24
store atomic i32 %add, ptr %a seq_cst, align 4, !dbg !25
%3 = load i32, ptr %y, align 4, !dbg !27
%add1 = add i32 33, %3, !dbg !28
store atomic volatile i32 %add1, ptr %a monotonic, align 4, !dbg !29
%4 = insertvalue %"any*" undef, ptr %a, 0, !dbg !31
%5 = insertvalue %"any*" %4, i64 ptrtoint (ptr @"$ct.int" to i64), 1, !dbg !31
%6 = getelementptr inbounds [1 x %"any*"], ptr %varargslots, i64 0, i64 0, !dbg !31
store %"any*" %5, ptr %6, align 16, !dbg !31
%7 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 2, ptr %varargslots, i64 1), !dbg !32
ret void, !dbg !32
}
define i32 @main(i32 %0, ptr %1) #0 !dbg !32 {
define i32 @main(i32 %0, ptr %1) #0 !dbg !33 {
entry:
call void @test.main(), !dbg !38
ret i32 0, !dbg !41
call void @test.main(), !dbg !39
ret i32 0, !dbg !42
}
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
@@ -68,47 +69,49 @@ declare i64 @std.io.printfn(ptr, ptr, i64, ptr, i64) #0
declare i1 @llvm.expect.i1(i1, i1) #2
!llvm.module.flags = !{!0, !1, !2}
!llvm.dbg.cu = !{!3}
!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.dbg.cu = !{!4}
!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 1, !"uwtable", i32 2}
!3 = distinct !DICompileUnit(language: DW_LANG_C11, file: !4, producer: "c3c", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false)
!4 = !DIFile(filename: "atomic_load_store_debug.c3"
!5 = distinct !DISubprogram(name: "main", linkageName: "test.main", scope: !4, file: !4, line: 10, type: !6, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !3, retainedNodes: !8)
!6 = !DISubroutineType(types: !7)
!7 = !{null}
!8 = !{}
!9 = !DILocalVariable(name: "a", scope: !5, file: !4, line: 12, type: !10, align: 4)
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!11 = !DILocation(line: 12, column: 6, scope: !5)
!12 = !DILocation(line: 12, column: 10, scope: !5)
!13 = !DILocalVariable(name: "x", scope: !5, file: !4, line: 13, type: !10, align: 4)
!14 = !DILocation(line: 13, column: 6, scope: !5)
!15 = !DILocation(line:
!16 = distinct !DILexicalBlock(scope: !5, file: !17,
!17 = !DIFile(filename: "mem.c3",
!18 = !DILocalVariable(name: "y", scope: !5, file: !4, line: 14, type: !10, align: 4)
!19 = !DILocation(line: 14, column: 6, scope: !5)
!20 = !DILocation(line:
!21 = distinct !DILexicalBlock(scope: !5, file: !17,
!22 = !DILocation(line: 15, column: 25, scope: !5)
!23 = !DILocation(line: 15, column: 19, scope: !5)
!24 = !DILocation(line:
!25 = distinct !DILexicalBlock(scope: !5, file: !17,
!26 = !DILocation(line: 16, column: 24, scope: !5)
!27 = !DILocation(line: 16, column: 19, scope: !5)
!28 = !DILocation(line:
!29 = distinct !DILexicalBlock(scope: !5, file: !17, line:
!30 = !DILocation(line: 17, column: 20, scope: !5)
!31 = !DILocation(line: 17, column: 6, scope: !5)
!32 = distinct !DISubprogram(name: "_$main", linkageName: "main", scope: !4, file: !4, line: 10, type: !33, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !3, retainedNodes: !8)
!33 = !DISubroutineType(types: !34)
!34 = !{!10, !10, !35}
!35 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "char**", baseType: !36, size: 64, align: 64, dwarfAddressSpace: 0)
!36 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "char*", baseType: !37, size: 64, align: 64, dwarfAddressSpace: 0)
!37 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char)
!38 = !DILocation(line: 18, column: 2, scope: !39)
!39 = distinct !DILexicalBlock(scope: !32, file: !40, line: 18, column: 2)
!40 = !DIFile(filename: "main_stub.c3",
!41 = !DILocation(line: 19, column: 9, scope: !39)
!2 = !{i32 2, !"frame-pointer", i32 2}
!3 = !{i32 1, !"uwtable", i32 2}
!4 = distinct !DICompileUnit(language: DW_LANG_C11, file: !5, producer: "c3c", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false)
!5 = !DIFile(filename: "atomic_load_store_debug.c3"
!6 = distinct !DISubprogram(name: "main", linkageName: "test.main", scope: !5, file: !5, line: 10, type: !7, scopeLine: 10, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !4, retainedNodes: !9)
!7 = !DISubroutineType(types: !8)
!8 = !{null}
!9 = !{}
!10 = !DILocalVariable(name: "a", scope: !6, file: !5, line: 12, type: !11, align: 4)
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!12 = !DILocation(line: 12, column: 6, scope: !6)
!13 = !DILocation(line: 12, column: 10, scope: !6)
!14 = !DILocalVariable(name: "x", scope: !6, file: !5, line: 13, type: !11, align: 4)
!15 = !DILocation(line: 13, column: 6, scope: !6)
!16 = !DILocation(line: 195, column: 23, scope: !17)
!17 = distinct !DILexicalBlock(scope: !6, file: !18, line: 195, column: 9)
!18 = !DIFile(filename: "mem.c3"
!19 = !DILocalVariable(name: "y", scope: !6, file: !5, line: 14, type: !11, align: 4)
!20 = !DILocation(line: 14, column: 6, scope: !6)
!21 = !DILocation(line: 195, column: 23, scope: !22)
!22 = distinct !DILexicalBlock(scope: !6, file: !18, line: 195, column: 9)
!23 = !DILocation(line: 15, column: 25, scope: !6)
!24 = !DILocation(line: 15, column: 19, scope: !6)
!25 = !DILocation(line: 210, column: 20, scope: !26)
!26 = distinct !DILexicalBlock(scope: !6, file: !18, line: 210, column: 2)
!27 = !DILocation(line: 16, column: 24, scope: !6)
!28 = !DILocation(line: 16, column: 19, scope: !6)
!29 = !DILocation(line: 210, column: 20, scope: !30)
!30 = distinct !DILexicalBlock(scope: !6, file: !18, line: 210, column: 2)
!31 = !DILocation(line: 17, column: 20, scope: !6)
!32 = !DILocation(line: 17, column: 6, scope: !6)
!33 = distinct !DISubprogram(name: "_$main", linkageName: "main"
!34 = !DISubroutineType(types: !35)
!35 = !{!11, !11, !36}
!36 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "char**", baseType: !37, size: 64, align: 64, dwarfAddressSpace: 0)
!37 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "char*", baseType: !38, size: 64, align: 64, dwarfAddressSpace: 0)
!38 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char)
!39 = !DILocation(line: 18, column: 2, scope: !40)
!40 = distinct !DILexicalBlock(scope: !33, file: !41, line: 18, column: 2)
!41 = !DIFile(filename: "main_stub.c3"
!42 = !DILocation(line: 19, column: 9, scope: !40)

View File

@@ -11,21 +11,22 @@ const FOO @private = ~(uint)(0);
@constants.BB = local_unnamed_addr constant i8 -56, align 1
@constants.CC = protected unnamed_addr constant i32 -1, align 4
@constants.FOO = protected unnamed_addr constant i32 -1, align 4
!llvm.module.flags = !{!0, !1, !2}
!llvm.dbg.cu = !{!3}
!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.dbg.cu = !{!4}
!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 1, !"uwtable", i32 2}
!3 = distinct !DICompileUnit(language: DW_LANG_C11, file: !4, producer: "c3c", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !5, splitDebugInlining: false)
!4 = !DIFile(filename: "constants.c3",
!5 = !{!6, !9, !11, !14}
!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression())
!7 = distinct !DIGlobalVariable(name: "AA", linkageName: "constants.AA", scope: !4
!8 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char)
!9 = !DIGlobalVariableExpression(var: !10, expr: !DIExpression())
!10 = distinct !DIGlobalVariable(name: "BB", linkageName: "constants.BB", scope: !4, file: !4, line: 2
!11 = !DIGlobalVariableExpression(var: !12, expr: !DIExpression())
!12 = distinct !DIGlobalVariable(name: "CC", linkageName: "constants.CC", scope: !4, file: !4, line: 3
!13 = !DIBasicType(name: "uint", size: 32, encoding: DW_ATE_unsigned)
!14 = !DIGlobalVariableExpression(var: !15, expr: !DIExpression())
!15 = distinct !DIGlobalVariable(name: "FOO", linkageName: "constants.FOO", scope: !4, file: !4, line:
!2 = !{i32 2, !"frame-pointer", i32 2}
!3 = !{i32 1, !"uwtable", i32 2}
!4 = distinct !DICompileUnit(language: DW_LANG_C11, file: !5, producer: "c3c", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !6, splitDebugInlining: false)
!5 = !DIFile(filename: "constants.c3",
!6 = !{!7, !10, !12, !15}
!7 = !DIGlobalVariableExpression(var: !8, expr: !DIExpression())
!8 = distinct !DIGlobalVariable(name: "AA", linkageName: "constants.AA", scope: !5
!9 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char)
!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression())
!11 = distinct !DIGlobalVariable(name: "BB", linkageName: "constants.BB", scope: !5, file: !5, line: 2
!12 = !DIGlobalVariableExpression(var: !13, expr: !DIExpression())
!13 = distinct !DIGlobalVariable(name: "CC", linkageName: "constants.CC", scope: !5, file: !5, line: 3
!14 = !DIBasicType(name: "uint", size: 32, encoding: DW_ATE_unsigned)
!15 = !DIGlobalVariableExpression(var: !16, expr: !DIExpression())
!16 = distinct !DIGlobalVariable(name: "FOO", linkageName: "constants.FOO", scope: !5, file: !5, line: 4, type: !14, isLocal: true, isDefinition: true, align: 4)

View File

@@ -12,27 +12,25 @@ const FOO @private = ~(uint)(0);
source_filename = "constants_mingw"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:
target triple = "x86_64-w64-windows-gnu"
@constants_mingw.AA = protected unnamed_addr constant i8 1, align 1
@constants_mingw.BB = local_unnamed_addr constant i8 -56, align 1
@constants_mingw.CC = protected unnamed_addr constant i32 -1, align 4
@constants_mingw.FOO = protected unnamed_addr constant i32 -1, align 4
!llvm.module.flags = !{!0, !1, !2}
!llvm.dbg.cu = !{!3}
!llvm.module.flags = !{!0, !1, !2, !3}
!llvm.dbg.cu = !{!4}
!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 1, !"uwtable", i32 2}
!3 = distinct !DICompileUnit(language: DW_LANG_C11, file: !4, producer: "c3c", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !5, splitDebugInlining: false)
!5 = !{!6, !9, !11, !14}
!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression())
!7 = distinct !DIGlobalVariable(name: "AA", linkageName: "constants_mingw.AA", scope: !4, file: !4, line: 1, type: !8, isLocal: true, isDefinition: true, align: 1)
!8 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char)
!9 = !DIGlobalVariableExpression(var: !10, expr: !DIExpression())
!10 = distinct !DIGlobalVariable(name: "BB", linkageName: "constants_mingw.BB", scope: !4, file: !4, line: 2, type: !8, isLocal: false, isDefinition: true, align: 1)
!11 = !DIGlobalVariableExpression(var: !12, expr: !DIExpression())
!12 = distinct !DIGlobalVariable(name: "CC", linkageName: "constants_mingw.CC", scope: !4, file: !4, line: 3, type: !13, isLocal: true, isDefinition: true, align: 4)
!13 = !DIBasicType(name: "uint", size: 32, encoding: DW_ATE_unsigned)
!14 = !DIGlobalVariableExpression(var: !15, expr: !DIExpression())
!15 = distinct !DIGlobalVariable(name: "FOO", linkageName: "constants_mingw.FOO", scope: !4, file: !4, line: 4, type: !13, isLocal: true, isDefinition: true, align: 4)
!2 = !{i32 2, !"frame-pointer", i32 2}
!3 = !{i32 1, !"uwtable", i32 2}
!4 = distinct !DICompileUnit(language: DW_LANG_C11, file: !5, producer: "c3c", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !6, splitDebugInlining: false)
!6 = !{!7, !10, !12, !15}
!7 = !DIGlobalVariableExpression(var: !8, expr: !DIExpression())
!8 = distinct !DIGlobalVariable(name: "AA", linkageName: "constants_mingw.AA", scope: !5, file: !5, line: 1, type: !9, isLocal: true, isDefinition: true, align: 1)
!9 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char)
!10 = !DIGlobalVariableExpression(var: !11, expr: !DIExpression())
!11 = distinct !DIGlobalVariable(name: "BB", linkageName: "constants_mingw.BB", scope: !5, file: !5, line: 2, type: !9, isLocal: false, isDefinition: true, align: 1)
!12 = !DIGlobalVariableExpression(var: !13, expr: !DIExpression())
!13 = distinct !DIGlobalVariable(name: "CC", linkageName: "constants_mingw.CC", scope: !5, file: !5, line: 3, type: !14, isLocal: true, isDefinition: true, align: 4)
!14 = !DIBasicType(name: "uint", size: 32, encoding: DW_ATE_unsigned)
!15 = !DIGlobalVariableExpression(var: !16, expr: !DIExpression())
!16 = distinct !DIGlobalVariable(name: "FOO", linkageName: "constants_mingw.FOO", scope: !5, file: !5, line: 4, type: !14, isLocal: true, isDefinition: true, align: 4)