authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-26 21:44:08-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-26 21:44:08-05:00
log6bfaf262d5a1d18482a813c7022ffb03a18f52a8
tree7f432e8f386aed17df3f1bccdff34ec58b3ff2af
parent8b716f941dbd43936a994a008aec9cd21d0b08f2
parent08dd1b553b37de24eaf24a37558b0f9993d4ca42

Merge branch 'master' into llvm6


98 files changed, 2293 insertions(+), 1690 deletions(-)

CMakeLists.txt+14-14
......@@ -49,6 +49,8 @@ option(ZIG_FORCE_EXTERNAL_LLD "If your system has the LLD patches use it instead
4949find_package(llvm)
5050find_package(clang)
5151
52set(ZIG_CPP_LIB_DIR "${CMAKE_BINARY_DIR}/zig_cpp")
53
5254if(ZIG_FORCE_EXTERNAL_LLD)
5355 find_package(lld)
5456 include_directories(${LLVM_INCLUDE_DIRS})
......@@ -192,6 +194,7 @@ else()
192194 embedded_lld_coff
193195 embedded_lld_lib
194196 )
197 install(TARGETS embedded_lld_elf embedded_lld_coff embedded_lld_lib DESTINATION "${ZIG_CPP_LIB_DIR}")
195198endif()
196199
197200# No patches have been applied to SoftFloat-3d
......@@ -345,6 +348,8 @@ set(ZIG_SOURCES
345348 "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp"
346349 "${CMAKE_SOURCE_DIR}/src/util.cpp"
347350 "${CMAKE_SOURCE_DIR}/src/translate_c.cpp"
351)
352set(ZIG_CPP_SOURCES
348353 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
349354)
350355
......@@ -390,6 +395,11 @@ if(ZIG_TEST_COVERAGE)
390395 set(EXE_LDFLAGS "${EXE_LDFLAGS} -fprofile-arcs -ftest-coverage")
391396endif()
392397
398add_library(zig_cpp STATIC ${ZIG_CPP_SOURCES})
399set_target_properties(zig_cpp PROPERTIES
400 COMPILE_FLAGS ${EXE_CFLAGS}
401)
402
393403add_executable(zig ${ZIG_SOURCES})
394404set_target_properties(zig PROPERTIES
395405 COMPILE_FLAGS ${EXE_CFLAGS}
......@@ -397,6 +407,7 @@ set_target_properties(zig PROPERTIES
397407)
398408
399409target_link_libraries(zig LINK_PUBLIC
410 zig_cpp
400411 ${SOFTFLOAT_LIBRARIES}
401412 ${CLANG_LIBRARIES}
402413 ${LLD_LIBRARIES}
......@@ -407,6 +418,7 @@ if(MSVC OR MINGW)
407418 target_link_libraries(zig LINK_PUBLIC version)
408419endif()
409420install(TARGETS zig DESTINATION bin)
421install(TARGETS zig_cpp DESTINATION "${ZIG_CPP_LIB_DIR}")
410422
411423install(FILES "${CMAKE_SOURCE_DIR}/c_headers/__clang_cuda_builtin_vars.h" DESTINATION "${C_HEADERS_DEST}")
412424install(FILES "${CMAKE_SOURCE_DIR}/c_headers/__clang_cuda_cmath.h" DESTINATION "${C_HEADERS_DEST}")
......@@ -516,7 +528,8 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST}
516528install(FILES "${CMAKE_SOURCE_DIR}/std/c/linux.zig" DESTINATION "${ZIG_STD_DEST}/c")
517529install(FILES "${CMAKE_SOURCE_DIR}/std/c/windows.zig" DESTINATION "${ZIG_STD_DEST}/c")
518530install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}")
519install(FILES "${CMAKE_SOURCE_DIR}/std/debug.zig" DESTINATION "${ZIG_STD_DEST}")
531install(FILES "${CMAKE_SOURCE_DIR}/std/debug/index.zig" DESTINATION "${ZIG_STD_DEST}/debug")
532install(FILES "${CMAKE_SOURCE_DIR}/std/debug/failing_allocator.zig" DESTINATION "${ZIG_STD_DEST}/debug")
520533install(FILES "${CMAKE_SOURCE_DIR}/std/dwarf.zig" DESTINATION "${ZIG_STD_DEST}")
521534install(FILES "${CMAKE_SOURCE_DIR}/std/elf.zig" DESTINATION "${ZIG_STD_DEST}")
522535install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}")
......@@ -618,16 +631,3 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/udivti3.zig" DESTINAT
618631install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/umodti3.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt")
619632install(FILES "${CMAKE_SOURCE_DIR}/std/special/panic.zig" DESTINATION "${ZIG_STD_DEST}/special")
620633install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special")
621
622if (ZIG_TEST_COVERAGE)
623 add_custom_target(coverage
624 WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
625 COMMAND lcov --directory . --zerocounters --rc lcov_branch_coverage=1
626 COMMAND ./zig build --build-file ../build.zig test
627 COMMAND lcov --directory . --capture --output-file coverage.info --rc lcov_branch_coverage=1
628 COMMAND lcov --remove coverage.info '/usr/*' --output-file coverage.info.cleaned --rc lcov_branch_coverage=1
629 COMMAND genhtml -o coverage coverage.info.cleaned --rc lcov_branch_coverage=1
630 COMMAND rm coverage.info coverage.info.cleaned
631 )
632endif()
633
README.md+10-20
......@@ -26,7 +26,7 @@ clarity.
2626 always compiled against statically in source form. Compile units do not
2727 depend on libc unless explicitly linked.
2828 * Nullable type instead of null pointers.
29 * Tagged union type instead of raw unions.
29 * Safe unions, tagged unions, and C ABI compatible unions.
3030 * Generics so that one can write efficient data structures that work for any
3131 data type.
3232 * No header files required. Top level declarations are entirely
......@@ -35,7 +35,7 @@ clarity.
3535 * Partial compile-time function evaluation with eliminates the need for
3636 a preprocessor or macros.
3737 * The binaries produced by Zig have complete debugging information so you can,
38 for example, use GDB to debug your software.
38 for example, use GDB or MSVC to debug your software.
3939 * Built-in unit tests with `zig test`.
4040 * Friendly toward package maintainers. Reproducible build, bootstrapping
4141 process carefully documented. Issues filed by package maintainers are
......@@ -78,10 +78,10 @@ that counts as "freestanding" for the purposes of this table.
7878
7979### Wanted: Windows Developers
8080
81Help get the tests passing on Windows, flesh out the standard library for
82Windows, streamline Zig installation and distribution for Windows. Work with
83LLVM and LLD teams to improve PDB/CodeView/MSVC debugging. Implement stack traces
84for Windows in the MinGW environment and the MSVC environment.
81Flesh out the standard library for Windows, streamline Zig installation and
82distribution for Windows. Work with LLVM and LLD teams to improve
83PDB/CodeView/MSVC debugging. Implement stack traces for Windows in the MinGW
84environment and the MSVC environment.
8585
8686### Wanted: MacOS and iOS Developers
8787
......@@ -178,6 +178,10 @@ Dependencies are the same as Stage 1, except now you have a working zig compiler
178178bin/zig build --build-file ../build.zig --prefix $(pwd)/stage2 install
179179```
180180
181This produces `./stage2/bin/zig` which can be used for testing and development.
182Once it is feature complete, it will be used to build stage 3 - the final compiler
183binary.
184
181185### Stage 3: Rebuild Self-Hosted Zig Using the Self-Hosted Compiler
182186
183187This is the actual compiler binary that we will install to the system.
......@@ -194,20 +198,6 @@ This is the actual compiler binary that we will install to the system.
194198./stage2/bin/zig build --build-file ../build.zig install -Drelease-fast
195199```
196200
197### Test Coverage
198
199To see test coverage in Zig, configure with `-DZIG_TEST_COVERAGE=ON` as an
200additional parameter to the Debug build.
201
202You must have `lcov` installed and available.
203
204Then `make coverage`.
205
206With GCC you will get a nice HTML view of the coverage data. With clang,
207the last step will fail, but you can execute
208`llvm-cov gcov $(find CMakeFiles/ -name "*.gcda")` and then inspect the
209produced .gcov files.
210
211201### Related Projects
212202
213203 * [zig-mode](https://github.com/AndreaOrru/zig-mode) - Emacs integration
build.zig+30-2
......@@ -1,3 +1,4 @@
1const builtin = @import("builtin");
12const std = @import("std");
23const Builder = std.build.Builder;
34const tests = @import("test/tests.zig");
......@@ -33,11 +34,32 @@ pub fn build(b: &Builder) {
3334 docs_step.dependOn(&docgen_home_cmd.step);
3435
3536 if (findLLVM(b)) |llvm| {
37 // find the stage0 build artifacts because we're going to re-use config.h and zig_cpp library
38 const build_info = b.exec([][]const u8{b.zig_exe, "BUILD_INFO"});
39 var build_info_it = mem.split(build_info, "\n");
40 const cmake_binary_dir = ??build_info_it.next();
41 const cxx_compiler = ??build_info_it.next();
42
3643 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
3744 exe.setBuildMode(mode);
38 exe.linkSystemLibrary("c");
45 exe.addIncludeDir("src");
46 exe.addIncludeDir(cmake_binary_dir);
47 addCppLib(b, exe, cmake_binary_dir, "libzig_cpp");
48 addCppLib(b, exe, cmake_binary_dir, "libembedded_lld_elf");
49 addCppLib(b, exe, cmake_binary_dir, "libembedded_lld_coff");
50 addCppLib(b, exe, cmake_binary_dir, "libembedded_lld_lib");
3951 dependOnLib(exe, llvm);
4052
53 if (!exe.target.isWindows()) {
54 const libstdcxx_path_padded = b.exec([][]const u8{cxx_compiler, "-print-file-name=libstdc++.a"});
55 const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\n").next();
56 exe.addObjectFile(libstdcxx_path);
57
58 exe.linkSystemLibrary("pthread");
59 }
60
61 exe.linkSystemLibrary("c");
62
4163 b.default_step.dependOn(&exe.step);
4264 b.default_step.dependOn(docs_step);
4365
......@@ -91,6 +113,11 @@ fn dependOnLib(lib_exe_obj: &std.build.LibExeObjStep, dep: &const LibraryDep) {
91113 }
92114}
93115
116fn addCppLib(b: &Builder, lib_exe_obj: &std.build.LibExeObjStep, cmake_binary_dir: []const u8, lib_name: []const u8) {
117 lib_exe_obj.addObjectFile(%%os.path.join(b.allocator, cmake_binary_dir, "zig_cpp",
118 b.fmt("{}{}", lib_name, lib_exe_obj.target.libFileExt())));
119}
120
94121const LibraryDep = struct {
95122 libdirs: ArrayList([]const u8),
96123 libs: ArrayList([]const u8),
......@@ -172,7 +199,8 @@ pub fn installStdLib(b: &Builder) {
172199 "c/linux.zig",
173200 "c/windows.zig",
174201 "cstr.zig",
175 "debug.zig",
202 "debug/failing_allocator.zig",
203 "debug/index.zig",
176204 "dwarf.zig",
177205 "elf.zig",
178206 "empty.zig",
doc/langref.html.in+9
......@@ -291,6 +291,15 @@ pub fn main() -&gt; %void {
291291 <li><a href="#errors">Errors</a></li>
292292 <li><a href="#root-source-file">Root Source File</a></li>
293293 </ul>
294 <h2 id="values">Source encoding</h2>
295 <p>Zig source code is encoded in UTF-8. An invalid UTF-8 byte sequence results in a compile error.</p>
296 <p>Throughout all zig source code (including in comments), some codepoints are never allowed:</p>
297 <ul>
298 <li>Ascii control characters, except for U+000a (LF): U+0000 - U+0009, U+000b - U+0001f, U+007f. (Note that Windows line endings (CRLF) are not allowed, and hard tabs are not allowed.)</li>
299 <li>Non-Ascii Unicode line endings: U+0085 (NEL), U+2028 (LS), U+2029 (PS).</li>
300 </ul>
301 <p>The codepoint U+000a (LF) (which is encoded as the single-byte value 0x0a) is the line terminator character. This character always terminates a line of zig source code. A non-empty zig source must end with the line terminator character.</p>
302 <p>For some discussion on the rationale behind these design decisions, see <a href="https://github.com/zig-lang/zig/issues/663">issue #663</a></p>
294303 <h2 id="values">Values</h2>
295304 <pre><code class="zig">const warn = @import("std").debug.warn;
296305const os = @import("std").os;
src-self-hosted/c.zig+2-5
......@@ -1,7 +1,4 @@
11pub use @cImport({
2 @cInclude("llvm-c/Core.h");
3 @cInclude("llvm-c/Analysis.h");
4 @cInclude("llvm-c/Target.h");
5 @cInclude("llvm-c/Initialization.h");
6 @cInclude("llvm-c/TargetMachine.h");
2 @cInclude("config.h");
3 @cInclude("zig_llvm.h");
74});
src-self-hosted/ir.zig created+112
......@@ -0,0 +1,112 @@
1const Scope = @import("scope.zig").Scope;
2
3pub const Instruction = struct {
4 id: Id,
5 scope: &Scope,
6
7 pub const Id = enum {
8 Br,
9 CondBr,
10 SwitchBr,
11 SwitchVar,
12 SwitchTarget,
13 Phi,
14 UnOp,
15 BinOp,
16 DeclVar,
17 LoadPtr,
18 StorePtr,
19 FieldPtr,
20 StructFieldPtr,
21 UnionFieldPtr,
22 ElemPtr,
23 VarPtr,
24 Call,
25 Const,
26 Return,
27 Cast,
28 ContainerInitList,
29 ContainerInitFields,
30 StructInit,
31 UnionInit,
32 Unreachable,
33 TypeOf,
34 ToPtrType,
35 PtrTypeChild,
36 SetDebugSafety,
37 SetFloatMode,
38 ArrayType,
39 SliceType,
40 Asm,
41 SizeOf,
42 TestNonNull,
43 UnwrapMaybe,
44 MaybeWrap,
45 UnionTag,
46 Clz,
47 Ctz,
48 Import,
49 CImport,
50 CInclude,
51 CDefine,
52 CUndef,
53 ArrayLen,
54 Ref,
55 MinValue,
56 MaxValue,
57 CompileErr,
58 CompileLog,
59 ErrName,
60 EmbedFile,
61 Cmpxchg,
62 Fence,
63 Truncate,
64 IntType,
65 BoolNot,
66 Memset,
67 Memcpy,
68 Slice,
69 MemberCount,
70 MemberType,
71 MemberName,
72 Breakpoint,
73 ReturnAddress,
74 FrameAddress,
75 AlignOf,
76 OverflowOp,
77 TestErr,
78 UnwrapErrCode,
79 UnwrapErrPayload,
80 ErrWrapCode,
81 ErrWrapPayload,
82 FnProto,
83 TestComptime,
84 PtrCast,
85 BitCast,
86 WidenOrShorten,
87 IntToPtr,
88 PtrToInt,
89 IntToEnum,
90 IntToErr,
91 ErrToInt,
92 CheckSwitchProngs,
93 CheckStatementIsVoid,
94 TypeName,
95 CanImplicitCast,
96 DeclRef,
97 Panic,
98 TagName,
99 TagType,
100 FieldParentPtr,
101 OffsetOf,
102 TypeId,
103 SetEvalBranchQuota,
104 PtrTypeOf,
105 AlignCast,
106 OpaqueType,
107 SetAlignStack,
108 ArgType,
109 Export,
110 };
111
112};
src-self-hosted/main.zig+6-1
......@@ -12,6 +12,7 @@ const ErrColor = Module.ErrColor;
1212const Emit = Module.Emit;
1313const builtin = @import("builtin");
1414const ArrayList = std.ArrayList;
15const c = @import("c.zig");
1516
1617error InvalidCommandLineArguments;
1718error ZigLibDirNotFound;
......@@ -462,7 +463,11 @@ pub fn main2() -> %void {
462463 else => unreachable,
463464 }
464465 },
465 Cmd.Version => @panic("TODO zig version"),
466 Cmd.Version => {
467 var stdout_file = %return io.getStdErr();
468 %return stdout_file.write(std.cstr.toSliceConst(c.ZIG_VERSION_STRING));
469 %return stdout_file.write("\n");
470 },
466471 Cmd.Targets => @panic("TODO zig targets"),
467472 }
468473}
src-self-hosted/module.zig+7
......@@ -199,6 +199,13 @@ pub const Module = struct {
199199 }
200200
201201 pub fn build(self: &Module) -> %void {
202 if (self.llvm_argv.len != 0) {
203 var c_compatible_args = %return std.cstr.NullTerminated2DArray.fromSlices(self.allocator,
204 [][]const []const u8 { [][]const u8{"zig (LLVM option parsing)"}, self.llvm_argv, });
205 defer c_compatible_args.deinit();
206 c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr);
207 }
208
202209 const root_src_path = self.root_src_path ?? @panic("TODO handle null root src path");
203210 const root_src_real_path = os.path.real(self.allocator, root_src_path) %% |err| {
204211 %return printError("unable to open '{}': {}", root_src_path, err);
src-self-hosted/parser.zig+18-12
......@@ -1119,18 +1119,24 @@ fn testCanonical(source: []const u8) {
11191119 break :x failing_allocator.index;
11201120 };
11211121
1122 // TODO make this pass
1123 //var fail_index = needed_alloc_count;
1124 //while (fail_index != 0) {
1125 // fail_index -= 1;
1126 // var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1127 // var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);
1128 // if (testParse(source, &failing_allocator.allocator)) |_| {
1129 // @panic("non-deterministic memory usage");
1130 // } else |err| {
1131 // assert(err == error.OutOfMemory);
1132 // }
1133 //}
1122 var fail_index: usize = 0;
1123 while (fail_index < needed_alloc_count) : (fail_index += 1) {
1124 var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]);
1125 var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index);
1126 if (testParse(source, &failing_allocator.allocator)) |_| {
1127 @panic("non-deterministic memory usage");
1128 } else |err| {
1129 assert(err == error.OutOfMemory);
1130 // TODO make this pass
1131 //if (failing_allocator.allocated_bytes != failing_allocator.freed_bytes) {
1132 // warn("\nfail_index: {}/{}\nallocated bytes: {}\nfreed bytes: {}\nallocations: {}\ndeallocations: {}\n",
1133 // fail_index, needed_alloc_count,
1134 // failing_allocator.allocated_bytes, failing_allocator.freed_bytes,
1135 // failing_allocator.index, failing_allocator.deallocations);
1136 // @panic("memory leak detected");
1137 //}
1138 }
1139 }
11341140}
11351141
11361142test "zig fmt" {
src-self-hosted/scope.zig created+16
......@@ -0,0 +1,16 @@
1pub const Scope = struct {
2 id: Id,
3 parent: &Scope,
4
5 pub const Id = enum {
6 Decls,
7 Block,
8 Defer,
9 DeferExpr,
10 VarDecl,
11 CImport,
12 Loop,
13 FnDef,
14 CompTime,
15 };
16};
src-self-hosted/tokenizer.zig+217-4
......@@ -70,6 +70,7 @@ pub const Token = struct {
7070 Identifier,
7171 StringLiteral: StrLitKind,
7272 Eof,
73 NoEolAtEof,
7374 Builtin,
7475 Bang,
7576 Equal,
......@@ -139,6 +140,8 @@ pub const Token = struct {
139140pub const Tokenizer = struct {
140141 buffer: []const u8,
141142 index: usize,
143 actual_file_end: usize,
144 pending_invalid_token: ?Token,
142145
143146 pub const Location = struct {
144147 line: usize,
......@@ -177,9 +180,17 @@ pub const Tokenizer = struct {
177180 }
178181
179182 pub fn init(buffer: []const u8) -> Tokenizer {
183 var source_len = buffer.len;
184 while (source_len > 0) : (source_len -= 1) {
185 if (buffer[source_len - 1] == '\n') break;
186 // last line is incomplete, so skip it, and give an error when we get there.
187 }
188
180189 return Tokenizer {
181 .buffer = buffer,
190 .buffer = buffer[0..source_len],
182191 .index = 0,
192 .actual_file_end = buffer.len,
193 .pending_invalid_token = null,
183194 };
184195 }
185196
......@@ -207,6 +218,10 @@ pub const Tokenizer = struct {
207218 };
208219
209220 pub fn next(self: &Tokenizer) -> Token {
221 if (self.pending_invalid_token) |token| {
222 self.pending_invalid_token = null;
223 return token;
224 }
210225 var state = State.Start;
211226 var result = Token {
212227 .id = Token.Id.Eof,
......@@ -352,7 +367,7 @@ pub const Tokenizer = struct {
352367 break;
353368 },
354369 '\n' => break, // Look for this error later.
355 else => {},
370 else => self.checkLiteralCharacter(),
356371 },
357372
358373 State.StringLiteralBackslash => switch (c) {
......@@ -439,7 +454,7 @@ pub const Tokenizer = struct {
439454 .end = undefined,
440455 };
441456 },
442 else => {},
457 else => self.checkLiteralCharacter(),
443458 },
444459 State.Zero => switch (c) {
445460 'b', 'o', 'x' => {
......@@ -497,13 +512,211 @@ pub const Tokenizer = struct {
497512 }
498513 }
499514 result.end = self.index;
500 // TODO check state when returning EOF
515 if (result.id == Token.Id.Eof) {
516 if (self.pending_invalid_token) |token| {
517 self.pending_invalid_token = null;
518 return token;
519 }
520 if (self.actual_file_end != self.buffer.len) {
521 // instead of an Eof, give an error token
522 result.id = Token.Id.NoEolAtEof;
523 result.end = self.actual_file_end;
524 }
525 }
501526 return result;
502527 }
503528
504529 pub fn getTokenSlice(self: &const Tokenizer, token: &const Token) -> []const u8 {
505530 return self.buffer[token.start..token.end];
506531 }
532
533 fn checkLiteralCharacter(self: &Tokenizer) {
534 if (self.pending_invalid_token != null) return;
535 const invalid_length = self.getInvalidCharacterLength();
536 if (invalid_length == 0) return;
537 self.pending_invalid_token = Token {
538 .id = Token.Id.Invalid,
539 .start = self.index,
540 .end = self.index + invalid_length,
541 };
542 }
543
544 fn getInvalidCharacterLength(self: &Tokenizer) -> u3 {
545 const c0 = self.buffer[self.index];
546 if (c0 < 0x80) {
547 if (c0 < 0x20 or c0 == 0x7f) {
548 // ascii control codes are never allowed
549 // (note that \n was checked before we got here)
550 return 1;
551 }
552 // looks fine to me.
553 return 0;
554 } else {
555 // check utf8-encoded character.
556 // remember that the last byte in the buffer is guaranteed to be '\n',
557 // which means we really don't need to do bounds checks here,
558 // as long as we check one byte at a time for being a continuation byte.
559 var value: u32 = undefined;
560 var length: u3 = undefined;
561 if (c0 & 0b11100000 == 0b11000000) {value = c0 & 0b00011111; length = 2;}
562 else if (c0 & 0b11110000 == 0b11100000) {value = c0 & 0b00001111; length = 3;}
563 else if (c0 & 0b11111000 == 0b11110000) {value = c0 & 0b00000111; length = 4;}
564 else return 1; // unexpected continuation or too many leading 1's
565
566 const c1 = self.buffer[self.index + 1];
567 if (c1 & 0b11000000 != 0b10000000) return 1; // expected continuation
568 value <<= 6;
569 value |= c1 & 0b00111111;
570 if (length == 2) {
571 if (value < 0x80) return length; // overlong
572 if (value == 0x85) return length; // U+0085 (NEL)
573 self.index += length - 1;
574 return 0;
575 }
576 const c2 = self.buffer[self.index + 2];
577 if (c2 & 0b11000000 != 0b10000000) return 2; // expected continuation
578 value <<= 6;
579 value |= c2 & 0b00111111;
580 if (length == 3) {
581 if (value < 0x800) return length; // overlong
582 if (value == 0x2028) return length; // U+2028 (LS)
583 if (value == 0x2029) return length; // U+2029 (PS)
584 if (0xd800 <= value and value <= 0xdfff) return length; // surrogate halves not allowed in utf8
585 self.index += length - 1;
586 return 0;
587 }
588 const c3 = self.buffer[self.index + 3];
589 if (c3 & 0b11000000 != 0b10000000) return 3; // expected continuation
590 value <<= 6;
591 value |= c3 & 0b00111111;
592 if (length == 4) {
593 if (value < 0x10000) return length; // overlong
594 if (value > 0x10FFFF) return length; // out of bounds
595 self.index += length - 1;
596 return 0;
597 }
598 unreachable;
599 }
600 }
507601};
508602
509603
604
605test "tokenizer - source must end with eol" {
606 testTokenizeWithEol("", []Token.Id {
607 }, true);
608 testTokenizeWithEol("no newline", []Token.Id {
609 }, false);
610 testTokenizeWithEol("test\n", []Token.Id {
611 Token.Id.Keyword_test,
612 }, true);
613 testTokenizeWithEol("test\nno newline", []Token.Id {
614 Token.Id.Keyword_test,
615 }, false);
616}
617
618test "tokenizer - invalid token characters" {
619 testTokenize("#\n", []Token.Id{Token.Id.Invalid});
620 testTokenize("`\n", []Token.Id{Token.Id.Invalid});
621}
622
623test "tokenizer - invalid literal/comment characters" {
624 testTokenize("\"\x00\"\n", []Token.Id {
625 Token.Id { .StringLiteral = Token.StrLitKind.Normal },
626 Token.Id.Invalid,
627 });
628 testTokenize("//\x00\n", []Token.Id {
629 Token.Id.Invalid,
630 });
631 testTokenize("//\x1f\n", []Token.Id {
632 Token.Id.Invalid,
633 });
634 testTokenize("//\x7f\n", []Token.Id {
635 Token.Id.Invalid,
636 });
637}
638
639test "tokenizer - valid unicode" {
640 testTokenize("//\xc2\x80\n", []Token.Id{});
641 testTokenize("//\xdf\xbf\n", []Token.Id{});
642 testTokenize("//\xe0\xa0\x80\n", []Token.Id{});
643 testTokenize("//\xe1\x80\x80\n", []Token.Id{});
644 testTokenize("//\xef\xbf\xbf\n", []Token.Id{});
645 testTokenize("//\xf0\x90\x80\x80\n", []Token.Id{});
646 testTokenize("//\xf1\x80\x80\x80\n", []Token.Id{});
647 testTokenize("//\xf3\xbf\xbf\xbf\n", []Token.Id{});
648 testTokenize("//\xf4\x8f\xbf\xbf\n", []Token.Id{});
649}
650
651test "tokenizer - invalid unicode continuation bytes" {
652 // unexpected continuation
653 testTokenize("//\x80\n", []Token.Id{Token.Id.Invalid});
654 testTokenize("//\xbf\n", []Token.Id{Token.Id.Invalid});
655 // too many leading 1's
656 testTokenize("//\xf8\n", []Token.Id{Token.Id.Invalid});
657 testTokenize("//\xff\n", []Token.Id{Token.Id.Invalid});
658 // expected continuation for 2 byte sequences
659 testTokenize("//\xc2\x00\n", []Token.Id{Token.Id.Invalid});
660 testTokenize("//\xc2\xc0\n", []Token.Id{Token.Id.Invalid});
661 // expected continuation for 3 byte sequences
662 testTokenize("//\xe0\x00\n", []Token.Id{Token.Id.Invalid});
663 testTokenize("//\xe0\xc0\n", []Token.Id{Token.Id.Invalid});
664 testTokenize("//\xe0\xa0\n", []Token.Id{Token.Id.Invalid});
665 testTokenize("//\xe0\xa0\x00\n", []Token.Id{Token.Id.Invalid});
666 testTokenize("//\xe0\xa0\xc0\n", []Token.Id{Token.Id.Invalid});
667 // expected continuation for 4 byte sequences
668 testTokenize("//\xf0\x00\n", []Token.Id{Token.Id.Invalid});
669 testTokenize("//\xf0\xc0\n", []Token.Id{Token.Id.Invalid});
670 testTokenize("//\xf0\x90\x00\n", []Token.Id{Token.Id.Invalid});
671 testTokenize("//\xf0\x90\xc0\n", []Token.Id{Token.Id.Invalid});
672 testTokenize("//\xf0\x90\x80\x00\n", []Token.Id{Token.Id.Invalid});
673 testTokenize("//\xf0\x90\x80\xc0\n", []Token.Id{Token.Id.Invalid});
674}
675
676test "tokenizer - overlong utf8 codepoint" {
677 testTokenize("//\xc0\x80\n", []Token.Id{Token.Id.Invalid});
678 testTokenize("//\xc1\xbf\n", []Token.Id{Token.Id.Invalid});
679 testTokenize("//\xe0\x80\x80\n", []Token.Id{Token.Id.Invalid});
680 testTokenize("//\xe0\x9f\xbf\n", []Token.Id{Token.Id.Invalid});
681 testTokenize("//\xf0\x80\x80\x80\n", []Token.Id{Token.Id.Invalid});
682 testTokenize("//\xf0\x8f\xbf\xbf\n", []Token.Id{Token.Id.Invalid});
683}
684
685test "tokenizer - misc invalid utf8" {
686 // codepoint out of bounds
687 testTokenize("//\xf4\x90\x80\x80\n", []Token.Id{Token.Id.Invalid});
688 testTokenize("//\xf7\xbf\xbf\xbf\n", []Token.Id{Token.Id.Invalid});
689 // unicode newline characters.U+0085, U+2028, U+2029
690 testTokenize("//\xc2\x84\n", []Token.Id{});
691 testTokenize("//\xc2\x85\n", []Token.Id{Token.Id.Invalid});
692 testTokenize("//\xc2\x86\n", []Token.Id{});
693 testTokenize("//\xe2\x80\xa7\n", []Token.Id{});
694 testTokenize("//\xe2\x80\xa8\n", []Token.Id{Token.Id.Invalid});
695 testTokenize("//\xe2\x80\xa9\n", []Token.Id{Token.Id.Invalid});
696 testTokenize("//\xe2\x80\xaa\n", []Token.Id{});
697 // surrogate halves
698 testTokenize("//\xed\x9f\x80\n", []Token.Id{});
699 testTokenize("//\xed\xa0\x80\n", []Token.Id{Token.Id.Invalid});
700 testTokenize("//\xed\xbf\xbf\n", []Token.Id{Token.Id.Invalid});
701 testTokenize("//\xee\x80\x80\n", []Token.Id{});
702 // surrogate halves are invalid, even in surrogate pairs
703 testTokenize("//\xed\xa0\xad\xed\xb2\xa9\n", []Token.Id{Token.Id.Invalid});
704}
705
706fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) {
707 testTokenizeWithEol(source, expected_tokens, true);
708}
709fn testTokenizeWithEol(source: []const u8, expected_tokens: []const Token.Id, expected_eol_at_eof: bool) {
710 var tokenizer = Tokenizer.init(source);
711 for (expected_tokens) |expected_token_id| {
712 const token = tokenizer.next();
713 std.debug.assert(@TagType(Token.Id)(token.id) == @TagType(Token.Id)(expected_token_id));
714 switch (expected_token_id) {
715 Token.Id.StringLiteral => |expected_kind| {
716 std.debug.assert(expected_kind == switch (token.id) { Token.Id.StringLiteral => |kind| kind, else => unreachable });
717 },
718 else => {},
719 }
720 }
721 std.debug.assert(tokenizer.next().id == if (expected_eol_at_eof) Token.Id.Eof else Token.Id.NoEolAtEof);
722}
src/all_types.hpp+1-1
......@@ -10,7 +10,7 @@
1010
1111#include "list.hpp"
1212#include "buffer.hpp"
13#include "zig_llvm.hpp"
13#include "zig_llvm.h"
1414#include "hash_map.hpp"
1515#include "errmsg.hpp"
1616#include "bigint.hpp"
src/analyze.cpp+1-1
......@@ -14,7 +14,7 @@
1414#include "os.hpp"
1515#include "parser.hpp"
1616#include "softfloat.hpp"
17#include "zig_llvm.hpp"
17#include "zig_llvm.h"
1818
1919
2020static const size_t default_backward_branch_quota = 1000;
src/codegen.cpp+20-8
......@@ -17,7 +17,7 @@
1717#include "os.hpp"
1818#include "translate_c.hpp"
1919#include "target.hpp"
20#include "zig_llvm.hpp"
20#include "zig_llvm.h"
2121
2222#include <stdio.h>
2323#include <errno.h>
......@@ -3705,12 +3705,24 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar
37053705 ConstParent *parent = &array_const_val->data.x_array.s_none.parent;
37063706 LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent);
37073707
3708 TypeTableEntry *usize = g->builtin_types.entry_usize;
3709 LLVMValueRef indices[] = {
3710 LLVMConstNull(usize->type_ref),
3711 LLVMConstInt(usize->type_ref, index, false),
3712 };
3713 return LLVMConstInBoundsGEP(base_ptr, indices, 2);
3708 LLVMTypeKind el_type = LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(base_ptr)));
3709 if (el_type == LLVMArrayTypeKind) {
3710 TypeTableEntry *usize = g->builtin_types.entry_usize;
3711 LLVMValueRef indices[] = {
3712 LLVMConstNull(usize->type_ref),
3713 LLVMConstInt(usize->type_ref, index, false),
3714 };
3715 return LLVMConstInBoundsGEP(base_ptr, indices, 2);
3716 } else if (el_type == LLVMStructTypeKind) {
3717 TypeTableEntry *u32 = g->builtin_types.entry_u32;
3718 LLVMValueRef indices[] = {
3719 LLVMConstNull(u32->type_ref),
3720 LLVMConstInt(u32->type_ref, index, false),
3721 };
3722 return LLVMConstInBoundsGEP(base_ptr, indices, 2);
3723 } else {
3724 zig_unreachable();
3725 }
37143726}
37153727
37163728static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index) {
......@@ -3732,7 +3744,7 @@ static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *un
37323744 TypeTableEntry *u32 = g->builtin_types.entry_u32;
37333745 LLVMValueRef indices[] = {
37343746 LLVMConstNull(u32->type_ref),
3735 LLVMConstInt(u32->type_ref, 0, false),
3747 LLVMConstInt(u32->type_ref, 0, false), // TODO test const union with more aligned tag type than payload
37363748 };
37373749 return LLVMConstInBoundsGEP(base_ptr, indices, 2);
37383750}
src/config.h.in+4
......@@ -24,4 +24,8 @@
2424// Only used for running tests before installing.
2525#define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test"
2626
27// Used for communicating build information to self hosted build.
28#define ZIG_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@"
29#define ZIG_CXX_COMPILER "@CMAKE_CXX_COMPILER@"
30
2731#endif
src/link.cpp+12-2
......@@ -351,6 +351,16 @@ static void coff_append_machine_arg(CodeGen *g, ZigList<const char *> *list) {
351351 }
352352}
353353
354static void link_diag_callback(void *context, const char *ptr, size_t len) {
355 Buf *diag = reinterpret_cast<Buf *>(context);
356 buf_append_mem(diag, ptr, len);
357}
358
359static bool zig_lld_link(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag) {
360 buf_resize(diag, 0);
361 return ZigLLDLink(oformat, args, arg_count, link_diag_callback, diag);
362}
363
354364static void construct_linker_job_coff(LinkJob *lj) {
355365 CodeGen *g = lj->codegen;
356366
......@@ -515,7 +525,7 @@ static void construct_linker_job_coff(LinkJob *lj) {
515525 gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path))));
516526 gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path))));
517527 Buf diag = BUF_INIT;
518 if (!ZigLLDLink(g->zig_target.oformat, gen_lib_args.items, gen_lib_args.length, &diag)) {
528 if (!zig_lld_link(g->zig_target.oformat, gen_lib_args.items, gen_lib_args.length, &diag)) {
519529 fprintf(stderr, "%s\n", buf_ptr(&diag));
520530 exit(1);
521531 }
......@@ -930,7 +940,7 @@ void codegen_link(CodeGen *g, const char *out_file) {
930940 Buf diag = BUF_INIT;
931941
932942 codegen_add_time_event(g, "LLVM Link");
933 if (!ZigLLDLink(g->zig_target.oformat, lj.args.items, lj.args.length, &diag)) {
943 if (!zig_lld_link(g->zig_target.oformat, lj.args.items, lj.args.length, &diag)) {
934944 fprintf(stderr, "%s\n", buf_ptr(&diag));
935945 exit(1);
936946 }
src/main.cpp+5
......@@ -266,6 +266,11 @@ static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) {
266266}
267267
268268int main(int argc, char **argv) {
269 if (argc == 2 && strcmp(argv[1], "BUILD_INFO") == 0) {
270 printf("%s\n%s\n", ZIG_CMAKE_BINARY_DIR, ZIG_CXX_COMPILER);
271 return 0;
272 }
273
269274 os_init();
270275
271276 char *arg0 = argv[0];
src/os.hpp+1-1
......@@ -11,7 +11,7 @@
1111#include "list.hpp"
1212#include "buffer.hpp"
1313#include "error.hpp"
14#include "zig_llvm.hpp"
14#include "zig_llvm.h"
1515
1616#include <stdio.h>
1717#include <inttypes.h>
src/target.hpp+1-1
......@@ -8,7 +8,7 @@
88#ifndef ZIG_TARGET_HPP
99#define ZIG_TARGET_HPP
1010
11#include <zig_llvm.hpp>
11#include <zig_llvm.h>
1212
1313struct Buf;
1414
src/util.hpp-2
......@@ -13,8 +13,6 @@
1313#include <string.h>
1414#include <assert.h>
1515
16#include <new>
17
1816#if defined(_MSC_VER)
1917
2018#include <intrin.h>
src/zig_llvm.cpp+65-29
......@@ -13,7 +13,7 @@
1313 * 3. Prevent C++ from infecting the rest of the project.
1414 */
1515
16#include "zig_llvm.hpp"
16#include "zig_llvm.h"
1717
1818#include <llvm/Analysis/TargetLibraryInfo.h>
1919#include <llvm/Analysis/TargetTransformInfo.h>
......@@ -39,8 +39,35 @@
3939
4040#include <lld/Common/Driver.h>
4141
42#include <new>
43
44#include <stdlib.h>
45
46#if defined(_MSC_VER)
47#define ATTRIBUTE_RETURNS_NOALIAS __declspec(restrict)
48#else
49#define ATTRIBUTE_RETURNS_NOALIAS __attribute__((__malloc__))
50#endif
51
4252using namespace llvm;
4353
54template<typename T, typename... Args>
55ATTRIBUTE_RETURNS_NOALIAS static inline T * create(Args... args) {
56 T * ptr = reinterpret_cast<T*>(malloc(sizeof(T)));
57 if (ptr == nullptr)
58 return nullptr;
59 new (ptr) T(args...);
60 return ptr;
61}
62
63template<typename T>
64static inline void destroy(T * ptr) {
65 if (ptr != nullptr) {
66 ptr[0].~T();
67 }
68 free(ptr);
69}
70
4471void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R) {
4572 initializeLoopStrengthReducePass(*unwrap(R));
4673}
......@@ -50,8 +77,7 @@ void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R) {
5077}
5178
5279char *ZigLLVMGetHostCPUName(void) {
53 std::string str = sys::getHostCPUName();
54 return strdup(str.c_str());
80 return strdup((const char *)sys::getHostCPUName().bytes_begin());
5581}
5682
5783char *ZigLLVMGetNativeFeatures(void) {
......@@ -63,11 +89,11 @@ char *ZigLLVMGetNativeFeatures(void) {
6389 features.AddFeature(F.first(), F.second);
6490 }
6591
66 return strdup(features.getString().c_str());
92 return strdup((const char *)StringRef(features.getString()).bytes_begin());
6793}
6894
6995static void addDiscriminatorsPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) {
70 PM.add(createAddDiscriminatorsPass());
96 PM.add(createAddDiscriminatorsPass());
7197}
7298
7399#ifndef NDEBUG
......@@ -82,7 +108,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
82108 std::error_code EC;
83109 raw_fd_ostream dest(filename, EC, sys::fs::F_None);
84110 if (EC) {
85 *error_message = strdup(EC.message().c_str());
111 *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
86112 return true;
87113 }
88114 TargetMachine* target_machine = reinterpret_cast<TargetMachine*>(targ_machine_ref);
......@@ -90,7 +116,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
90116
91117 Module* module = unwrap(module_ref);
92118
93 PassManagerBuilder *PMBuilder = new PassManagerBuilder();
119 PassManagerBuilder *PMBuilder = create<PassManagerBuilder>();
94120 PMBuilder->OptLevel = target_machine->getOptLevel();
95121 PMBuilder->SizeLevel = 0;
96122
......@@ -123,7 +149,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
123149
124150 // Set up the per-function pass manager.
125151 legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module);
126 FPM.add(new TargetLibraryInfoWrapperPass(tlii));
152 FPM.add(create<TargetLibraryInfoWrapperPass>(tlii));
127153 FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis()));
128154 if (assertions_on) {
129155 FPM.add(createVerifierPass());
......@@ -415,7 +441,10 @@ unsigned ZigLLVMTag_DW_union_type(void) {
415441}
416442
417443ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) {
418 DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved);
444 DIBuilder *di_builder = reinterpret_cast<DIBuilder*>(malloc(sizeof(DIBuilder)));
445 if (di_builder == nullptr)
446 return nullptr;
447 new (di_builder) DIBuilder(*unwrap(module), allow_unresolved);
419448 return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder);
420449}
421450
......@@ -617,7 +646,7 @@ void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn_ref) {
617646 func->setAttributes(new_attr_set);
618647}
619648
620void ZigLLVMParseCommandLineOptions(int argc, const char *const *argv) {
649void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {
621650 llvm::cl::ParseCommandLineOptions(argc, argv);
622651}
623652
......@@ -775,29 +804,35 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV
775804}
776805
777806
778#include "buffer.hpp"
807class MyOStream: public raw_ostream {
808 public:
809 MyOStream(void (*_append_diagnostic)(void *, const char *, size_t), void *_context) :
810 raw_ostream(true), append_diagnostic(_append_diagnostic), context(_context), pos(0) {
811
812 }
813 void write_impl(const char *ptr, size_t len) override {
814 append_diagnostic(context, ptr, len);
815 pos += len;
816 }
817 uint64_t current_pos() const override {
818 return pos;
819 }
820 void (*append_diagnostic)(void *, const char *, size_t);
821 void *context;
822 size_t pos;
823};
824
779825
780bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag_buf) {
826bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count,
827 void (*append_diagnostic)(void *, const char *, size_t), void *context)
828{
781829 ArrayRef<const char *> array_ref_args(args, arg_count);
782830
783 buf_resize(diag_buf, 0);
784 class MyOStream: public raw_ostream {
785 public:
786 MyOStream(Buf *_diag_buf) : raw_ostream(true), diag_buf(_diag_buf) {
787
788 }
789 void write_impl(const char *ptr, size_t len) override {
790 buf_append_mem(diag_buf, ptr, len);
791 }
792 uint64_t current_pos() const override {
793 return buf_len(diag_buf);
794 }
795 Buf *diag_buf;
796 } diag(diag_buf);
831 MyOStream diag(append_diagnostic, context);
797832
798833 switch (oformat) {
799834 case ZigLLVM_UnknownObjectFormat:
800 zig_unreachable();
835 assert(false); // unreachable
801836
802837 case ZigLLVM_COFF:
803838 return lld::coff::link(array_ref_args, false, diag);
......@@ -809,7 +844,8 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_
809844 return lld::mach_o::link(array_ref_args, diag);
810845
811846 case ZigLLVM_Wasm:
812 zig_panic("ZigLLDLink for Wasm");
847 assert(false); // TODO ZigLLDLink for Wasm
813848 }
814 zig_unreachable();
849 assert(false); // unreachable
850 abort();
815851}
src/zig_llvm.h created+398
......@@ -0,0 +1,398 @@
1/*
2 * Copyright (c) 2015 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_ZIG_LLVM_HPP
9#define ZIG_ZIG_LLVM_HPP
10
11#include <stdbool.h>
12#include <stddef.h>
13#include <llvm-c/Core.h>
14#include <llvm-c/Analysis.h>
15#include <llvm-c/Target.h>
16#include <llvm-c/Initialization.h>
17#include <llvm-c/TargetMachine.h>
18
19#ifdef __cplusplus
20#define ZIG_EXTERN_C extern "C"
21#else
22#define ZIG_EXTERN_C
23#endif
24
25struct ZigLLVMDIType;
26struct ZigLLVMDIBuilder;
27struct ZigLLVMDICompileUnit;
28struct ZigLLVMDIScope;
29struct ZigLLVMDIFile;
30struct ZigLLVMDILexicalBlock;
31struct ZigLLVMDISubprogram;
32struct ZigLLVMDISubroutineType;
33struct ZigLLVMDILocalVariable;
34struct ZigLLVMDIGlobalVariable;
35struct ZigLLVMDILocation;
36struct ZigLLVMDIEnumerator;
37struct ZigLLVMInsertionPoint;
38
39ZIG_EXTERN_C void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R);
40ZIG_EXTERN_C void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R);
41
42/// Caller must free memory.
43ZIG_EXTERN_C char *ZigLLVMGetHostCPUName(void);
44ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void);
45
46// We use a custom enum here since LLVM does not expose LLVMIr as an emit
47// output through the same mechanism as assembly/binary.
48enum ZigLLVM_EmitOutputType {
49 ZigLLVM_EmitAssembly,
50 ZigLLVM_EmitBinary,
51 ZigLLVM_EmitLLVMIr,
52};
53
54ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
55 const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug);
56
57enum ZigLLVM_FnInline {
58 ZigLLVM_FnInlineAuto,
59 ZigLLVM_FnInlineAlways,
60 ZigLLVM_FnInlineNever,
61};
62ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
63 unsigned NumArgs, unsigned CC, enum ZigLLVM_FnInline fn_inline, const char *Name);
64
65ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
66 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
67 LLVMAtomicOrdering failure_ordering);
68
69ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
70 const char *name);
71ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
72 const char *name);
73ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
74 const char *name);
75ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
76 const char *name);
77
78ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugPointerType(struct ZigLLVMDIBuilder *dibuilder,
79 struct ZigLLVMDIType *pointee_type, uint64_t size_in_bits, uint64_t align_in_bits, const char *name);
80
81ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugBasicType(struct ZigLLVMDIBuilder *dibuilder, const char *name,
82 uint64_t size_in_bits, unsigned encoding);
83
84ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugArrayType(struct ZigLLVMDIBuilder *dibuilder,
85 uint64_t size_in_bits, uint64_t align_in_bits, struct ZigLLVMDIType *elem_type,
86 int elem_count);
87
88ZIG_EXTERN_C struct ZigLLVMDIEnumerator *ZigLLVMCreateDebugEnumerator(struct ZigLLVMDIBuilder *dibuilder,
89 const char *name, int64_t val);
90
91ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugEnumerationType(struct ZigLLVMDIBuilder *dibuilder,
92 struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line_number,
93 uint64_t size_in_bits, uint64_t align_in_bits, struct ZigLLVMDIEnumerator **enumerator_array,
94 int enumerator_array_len, struct ZigLLVMDIType *underlying_type, const char *unique_id);
95
96ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugStructType(struct ZigLLVMDIBuilder *dibuilder,
97 struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line_number,
98 uint64_t size_in_bits, uint64_t align_in_bits, unsigned flags, struct ZigLLVMDIType *derived_from,
99 struct ZigLLVMDIType **types_array, int types_array_len, unsigned run_time_lang,
100 struct ZigLLVMDIType *vtable_holder, const char *unique_id);
101
102ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugUnionType(struct ZigLLVMDIBuilder *dibuilder,
103 struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line_number,
104 uint64_t size_in_bits, uint64_t align_in_bits, unsigned flags, struct ZigLLVMDIType **types_array,
105 int types_array_len, unsigned run_time_lang, const char *unique_id);
106
107ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugMemberType(struct ZigLLVMDIBuilder *dibuilder,
108 struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line,
109 uint64_t size_in_bits, uint64_t align_in_bits, uint64_t offset_in_bits, unsigned flags,
110 struct ZigLLVMDIType *type);
111
112ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateReplaceableCompositeType(struct ZigLLVMDIBuilder *dibuilder,
113 unsigned tag, const char *name, struct ZigLLVMDIScope *scope, struct ZigLLVMDIFile *file, unsigned line);
114
115ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugForwardDeclType(struct ZigLLVMDIBuilder *dibuilder, unsigned tag,
116 const char *name, struct ZigLLVMDIScope *scope, struct ZigLLVMDIFile *file, unsigned line);
117
118ZIG_EXTERN_C void ZigLLVMReplaceTemporary(struct ZigLLVMDIBuilder *dibuilder, struct ZigLLVMDIType *type,
119 struct ZigLLVMDIType *replacement);
120
121ZIG_EXTERN_C void ZigLLVMReplaceDebugArrays(struct ZigLLVMDIBuilder *dibuilder, struct ZigLLVMDIType *type,
122 struct ZigLLVMDIType **types_array, int types_array_len);
123
124ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateSubroutineType(struct ZigLLVMDIBuilder *dibuilder_wrapped,
125 struct ZigLLVMDIType **types_array, int types_array_len, unsigned flags);
126
127ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_unsigned(void);
128ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_signed(void);
129ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_float(void);
130ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_boolean(void);
131ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_unsigned_char(void);
132ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_signed_char(void);
133ZIG_EXTERN_C unsigned ZigLLVMLang_DW_LANG_C99(void);
134ZIG_EXTERN_C unsigned ZigLLVMTag_DW_variable(void);
135ZIG_EXTERN_C unsigned ZigLLVMTag_DW_structure_type(void);
136ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void);
137
138ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);
139ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);
140ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module);
141
142ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column,
143 struct ZigLLVMDIScope *scope);
144ZIG_EXTERN_C void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder);
145
146ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMLexicalBlockToScope(struct ZigLLVMDILexicalBlock *lexical_block);
147ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMCompileUnitToScope(struct ZigLLVMDICompileUnit *compile_unit);
148ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMFileToScope(struct ZigLLVMDIFile *difile);
149ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMSubprogramToScope(struct ZigLLVMDISubprogram *subprogram);
150ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMTypeToScope(struct ZigLLVMDIType *type);
151
152ZIG_EXTERN_C struct ZigLLVMDILocalVariable *ZigLLVMCreateAutoVariable(struct ZigLLVMDIBuilder *dbuilder,
153 struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line_no,
154 struct ZigLLVMDIType *type, bool always_preserve, unsigned flags);
155
156ZIG_EXTERN_C struct ZigLLVMDIGlobalVariable *ZigLLVMCreateGlobalVariable(struct ZigLLVMDIBuilder *dbuilder,
157 struct ZigLLVMDIScope *scope, const char *name, const char *linkage_name, struct ZigLLVMDIFile *file,
158 unsigned line_no, struct ZigLLVMDIType *di_type, bool is_local_to_unit);
159
160ZIG_EXTERN_C struct ZigLLVMDILocalVariable *ZigLLVMCreateParameterVariable(struct ZigLLVMDIBuilder *dbuilder,
161 struct ZigLLVMDIScope *scope, const char *name, struct ZigLLVMDIFile *file, unsigned line_no,
162 struct ZigLLVMDIType *type, bool always_preserve, unsigned flags, unsigned arg_no);
163
164ZIG_EXTERN_C struct ZigLLVMDILexicalBlock *ZigLLVMCreateLexicalBlock(struct ZigLLVMDIBuilder *dbuilder,
165 struct ZigLLVMDIScope *scope, struct ZigLLVMDIFile *file, unsigned line, unsigned col);
166
167ZIG_EXTERN_C struct ZigLLVMDICompileUnit *ZigLLVMCreateCompileUnit(struct ZigLLVMDIBuilder *dibuilder,
168 unsigned lang, struct ZigLLVMDIFile *difile, const char *producer,
169 bool is_optimized, const char *flags, unsigned runtime_version, const char *split_name,
170 uint64_t dwo_id, bool emit_debug_info);
171
172ZIG_EXTERN_C struct ZigLLVMDIFile *ZigLLVMCreateFile(struct ZigLLVMDIBuilder *dibuilder, const char *filename,
173 const char *directory);
174
175ZIG_EXTERN_C struct ZigLLVMDISubprogram *ZigLLVMCreateFunction(struct ZigLLVMDIBuilder *dibuilder,
176 struct ZigLLVMDIScope *scope, const char *name, const char *linkage_name, struct ZigLLVMDIFile *file,
177 unsigned lineno, struct ZigLLVMDIType *fn_di_type, bool is_local_to_unit, bool is_definition,
178 unsigned scope_line, unsigned flags, bool is_optimized, struct ZigLLVMDISubprogram *decl_subprogram);
179
180ZIG_EXTERN_C void ZigLLVMFnSetSubprogram(LLVMValueRef fn, struct ZigLLVMDISubprogram *subprogram);
181
182ZIG_EXTERN_C void ZigLLVMDIBuilderFinalize(struct ZigLLVMDIBuilder *dibuilder);
183
184ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclareAtEnd(struct ZigLLVMDIBuilder *dibuilder, LLVMValueRef storage,
185 struct ZigLLVMDILocalVariable *var_info, struct ZigLLVMDILocation *debug_loc,
186 LLVMBasicBlockRef basic_block_ref);
187
188ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclare(struct ZigLLVMDIBuilder *dibuilder, LLVMValueRef storage,
189 struct ZigLLVMDILocalVariable *var_info, struct ZigLLVMDILocation *debug_loc, LLVMValueRef insert_before_instr);
190ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, struct ZigLLVMDIScope *scope);
191
192ZIG_EXTERN_C void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);
193
194ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);
195ZIG_EXTERN_C void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn);
196
197ZIG_EXTERN_C void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv);
198
199
200// copied from include/llvm/ADT/Triple.h
201
202enum ZigLLVM_ArchType {
203 ZigLLVM_UnknownArch,
204
205 ZigLLVM_arm, // ARM (little endian): arm, armv.*, xscale
206 ZigLLVM_armeb, // ARM (big endian): armeb
207 ZigLLVM_aarch64, // AArch64 (little endian): aarch64
208 ZigLLVM_aarch64_be, // AArch64 (big endian): aarch64_be
209 ZigLLVM_arc, // ARC: Synopsys ARC
210 ZigLLVM_avr, // AVR: Atmel AVR microcontroller
211 ZigLLVM_bpfel, // eBPF or extended BPF or 64-bit BPF (little endian)
212 ZigLLVM_bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian)
213 ZigLLVM_hexagon, // Hexagon: hexagon
214 ZigLLVM_mips, // MIPS: mips, mipsallegrex
215 ZigLLVM_mipsel, // MIPSEL: mipsel, mipsallegrexel
216 ZigLLVM_mips64, // MIPS64: mips64
217 ZigLLVM_mips64el, // MIPS64EL: mips64el
218 ZigLLVM_msp430, // MSP430: msp430
219 ZigLLVM_nios2, // NIOSII: nios2
220 ZigLLVM_ppc, // PPC: powerpc
221 ZigLLVM_ppc64, // PPC64: powerpc64, ppu
222 ZigLLVM_ppc64le, // PPC64LE: powerpc64le
223 ZigLLVM_r600, // R600: AMD GPUs HD2XXX - HD6XXX
224 ZigLLVM_amdgcn, // AMDGCN: AMD GCN GPUs
225 ZigLLVM_riscv32, // RISC-V (32-bit): riscv32
226 ZigLLVM_riscv64, // RISC-V (64-bit): riscv64
227 ZigLLVM_sparc, // Sparc: sparc
228 ZigLLVM_sparcv9, // Sparcv9: Sparcv9
229 ZigLLVM_sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant
230 ZigLLVM_systemz, // SystemZ: s390x
231 ZigLLVM_tce, // TCE (http://tce.cs.tut.fi/): tce
232 ZigLLVM_tcele, // TCE little endian (http://tce.cs.tut.fi/): tcele
233 ZigLLVM_thumb, // Thumb (little endian): thumb, thumbv.*
234 ZigLLVM_thumbeb, // Thumb (big endian): thumbeb
235 ZigLLVM_x86, // X86: i[3-9]86
236 ZigLLVM_x86_64, // X86-64: amd64, x86_64
237 ZigLLVM_xcore, // XCore: xcore
238 ZigLLVM_nvptx, // NVPTX: 32-bit
239 ZigLLVM_nvptx64, // NVPTX: 64-bit
240 ZigLLVM_le32, // le32: generic little-endian 32-bit CPU (PNaCl)
241 ZigLLVM_le64, // le64: generic little-endian 64-bit CPU (PNaCl)
242 ZigLLVM_amdil, // AMDIL
243 ZigLLVM_amdil64, // AMDIL with 64-bit pointers
244 ZigLLVM_hsail, // AMD HSAIL
245 ZigLLVM_hsail64, // AMD HSAIL with 64-bit pointers
246 ZigLLVM_spir, // SPIR: standard portable IR for OpenCL 32-bit version
247 ZigLLVM_spir64, // SPIR: standard portable IR for OpenCL 64-bit version
248 ZigLLVM_kalimba, // Kalimba: generic kalimba
249 ZigLLVM_shave, // SHAVE: Movidius vector VLIW processors
250 ZigLLVM_lanai, // Lanai: Lanai 32-bit
251 ZigLLVM_wasm32, // WebAssembly with 32-bit pointers
252 ZigLLVM_wasm64, // WebAssembly with 64-bit pointers
253 ZigLLVM_renderscript32, // 32-bit RenderScript
254 ZigLLVM_renderscript64, // 64-bit RenderScript
255
256 ZigLLVM_LastArchType = ZigLLVM_renderscript64
257};
258
259enum ZigLLVM_SubArchType {
260 ZigLLVM_NoSubArch,
261
262 ZigLLVM_ARMSubArch_v8_3a,
263 ZigLLVM_ARMSubArch_v8_2a,
264 ZigLLVM_ARMSubArch_v8_1a,
265 ZigLLVM_ARMSubArch_v8,
266 ZigLLVM_ARMSubArch_v8r,
267 ZigLLVM_ARMSubArch_v8m_baseline,
268 ZigLLVM_ARMSubArch_v8m_mainline,
269 ZigLLVM_ARMSubArch_v7,
270 ZigLLVM_ARMSubArch_v7em,
271 ZigLLVM_ARMSubArch_v7m,
272 ZigLLVM_ARMSubArch_v7s,
273 ZigLLVM_ARMSubArch_v7k,
274 ZigLLVM_ARMSubArch_v7ve,
275 ZigLLVM_ARMSubArch_v6,
276 ZigLLVM_ARMSubArch_v6m,
277 ZigLLVM_ARMSubArch_v6k,
278 ZigLLVM_ARMSubArch_v6t2,
279 ZigLLVM_ARMSubArch_v5,
280 ZigLLVM_ARMSubArch_v5te,
281 ZigLLVM_ARMSubArch_v4t,
282
283 ZigLLVM_KalimbaSubArch_v3,
284 ZigLLVM_KalimbaSubArch_v4,
285 ZigLLVM_KalimbaSubArch_v5,
286};
287
288enum ZigLLVM_VendorType {
289 ZigLLVM_UnknownVendor,
290
291 ZigLLVM_Apple,
292 ZigLLVM_PC,
293 ZigLLVM_SCEI,
294 ZigLLVM_BGP,
295 ZigLLVM_BGQ,
296 ZigLLVM_Freescale,
297 ZigLLVM_IBM,
298 ZigLLVM_ImaginationTechnologies,
299 ZigLLVM_MipsTechnologies,
300 ZigLLVM_NVIDIA,
301 ZigLLVM_CSR,
302 ZigLLVM_Myriad,
303 ZigLLVM_AMD,
304 ZigLLVM_Mesa,
305 ZigLLVM_SUSE,
306
307 ZigLLVM_LastVendorType = ZigLLVM_SUSE
308};
309
310enum ZigLLVM_OSType {
311 ZigLLVM_UnknownOS,
312
313 ZigLLVM_Ananas,
314 ZigLLVM_CloudABI,
315 ZigLLVM_Darwin,
316 ZigLLVM_DragonFly,
317 ZigLLVM_FreeBSD,
318 ZigLLVM_Fuchsia,
319 ZigLLVM_IOS,
320 ZigLLVM_KFreeBSD,
321 ZigLLVM_Linux,
322 ZigLLVM_Lv2, // PS3
323 ZigLLVM_MacOSX,
324 ZigLLVM_NetBSD,
325 ZigLLVM_OpenBSD,
326 ZigLLVM_Solaris,
327 ZigLLVM_Win32,
328 ZigLLVM_Haiku,
329 ZigLLVM_Minix,
330 ZigLLVM_RTEMS,
331 ZigLLVM_NaCl, // Native Client
332 ZigLLVM_CNK, // BG/P Compute-Node Kernel
333 ZigLLVM_Bitrig,
334 ZigLLVM_AIX,
335 ZigLLVM_CUDA, // NVIDIA CUDA
336 ZigLLVM_NVCL, // NVIDIA OpenCL
337 ZigLLVM_AMDHSA, // AMD HSA Runtime
338 ZigLLVM_PS4,
339 ZigLLVM_ELFIAMCU,
340 ZigLLVM_TvOS, // Apple tvOS
341 ZigLLVM_WatchOS, // Apple watchOS
342 ZigLLVM_Mesa3D,
343 ZigLLVM_Contiki,
344
345 ZigLLVM_LastOSType = ZigLLVM_Contiki
346};
347
348enum ZigLLVM_EnvironmentType {
349 ZigLLVM_UnknownEnvironment,
350
351 ZigLLVM_GNU,
352 ZigLLVM_GNUABIN32,
353 ZigLLVM_GNUABI64,
354 ZigLLVM_GNUEABI,
355 ZigLLVM_GNUEABIHF,
356 ZigLLVM_GNUX32,
357 ZigLLVM_CODE16,
358 ZigLLVM_EABI,
359 ZigLLVM_EABIHF,
360 ZigLLVM_Android,
361 ZigLLVM_Musl,
362 ZigLLVM_MuslEABI,
363 ZigLLVM_MuslEABIHF,
364
365 ZigLLVM_MSVC,
366 ZigLLVM_Itanium,
367 ZigLLVM_Cygnus,
368 ZigLLVM_AMDOpenCL,
369 ZigLLVM_CoreCLR,
370 ZigLLVM_OpenCL,
371 ZigLLVM_Simulator,
372
373 ZigLLVM_LastEnvironmentType = ZigLLVM_Simulator
374};
375
376enum ZigLLVM_ObjectFormatType {
377 ZigLLVM_UnknownObjectFormat,
378
379 ZigLLVM_COFF,
380 ZigLLVM_ELF,
381 ZigLLVM_MachO,
382 ZigLLVM_Wasm,
383};
384
385ZIG_EXTERN_C const char *ZigLLVMGetArchTypeName(enum ZigLLVM_ArchType arch);
386ZIG_EXTERN_C const char *ZigLLVMGetSubArchTypeName(enum ZigLLVM_SubArchType sub_arch);
387ZIG_EXTERN_C const char *ZigLLVMGetVendorTypeName(enum ZigLLVM_VendorType vendor);
388ZIG_EXTERN_C const char *ZigLLVMGetOSTypeName(enum ZigLLVM_OSType os);
389ZIG_EXTERN_C const char *ZigLLVMGetEnvironmentTypeName(enum ZigLLVM_EnvironmentType env_type);
390
391ZIG_EXTERN_C bool ZigLLDLink(enum ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count,
392 void (*append_diagnostic)(void *, const char *, size_t), void *context);
393
394ZIG_EXTERN_C void ZigLLVMGetNativeTarget(enum ZigLLVM_ArchType *arch_type, enum ZigLLVM_SubArchType *sub_arch_type,
395 enum ZigLLVM_VendorType *vendor_type, enum ZigLLVM_OSType *os_type, enum ZigLLVM_EnvironmentType *environ_type,
396 enum ZigLLVM_ObjectFormatType *oformat);
397
398#endif
src/zig_llvm.hpp deleted-387
......@@ -1,387 +0,0 @@
1/*
2 * Copyright (c) 2015 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_ZIG_LLVM_HPP
9#define ZIG_ZIG_LLVM_HPP
10
11#include <llvm-c/Core.h>
12#include <llvm-c/Analysis.h>
13#include <llvm-c/Target.h>
14#include <llvm-c/Initialization.h>
15#include <llvm-c/TargetMachine.h>
16
17struct ZigLLVMDIType;
18struct ZigLLVMDIBuilder;
19struct ZigLLVMDICompileUnit;
20struct ZigLLVMDIScope;
21struct ZigLLVMDIFile;
22struct ZigLLVMDILexicalBlock;
23struct ZigLLVMDISubprogram;
24struct ZigLLVMDISubroutineType;
25struct ZigLLVMDILocalVariable;
26struct ZigLLVMDIGlobalVariable;
27struct ZigLLVMDILocation;
28struct ZigLLVMDIEnumerator;
29struct ZigLLVMInsertionPoint;
30
31void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R);
32void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R);
33
34char *ZigLLVMGetHostCPUName(void);
35char *ZigLLVMGetNativeFeatures(void);
36
37// We use a custom enum here since LLVM does not expose LLVMIr as an emit
38// output through the same mechanism as assembly/binary.
39enum ZigLLVM_EmitOutputType {
40 ZigLLVM_EmitAssembly,
41 ZigLLVM_EmitBinary,
42 ZigLLVM_EmitLLVMIr,
43};
44
45bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
46 const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug);
47
48enum ZigLLVM_FnInline {
49 ZigLLVM_FnInlineAuto,
50 ZigLLVM_FnInlineAlways,
51 ZigLLVM_FnInlineNever,
52};
53LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args,
54 unsigned NumArgs, unsigned CC, ZigLLVM_FnInline fn_inline, const char *Name);
55
56LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp,
57 LLVMValueRef new_val, LLVMAtomicOrdering success_ordering,
58 LLVMAtomicOrdering failure_ordering);
59
60LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
61 const char *name);
62LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
63 const char *name);
64LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
65 const char *name);
66LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
67 const char *name);
68
69ZigLLVMDIType *ZigLLVMCreateDebugPointerType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *pointee_type,
70 uint64_t size_in_bits, uint64_t align_in_bits, const char *name);
71
72ZigLLVMDIType *ZigLLVMCreateDebugBasicType(ZigLLVMDIBuilder *dibuilder, const char *name,
73 uint64_t size_in_bits, unsigned encoding);
74
75ZigLLVMDIType *ZigLLVMCreateDebugArrayType(ZigLLVMDIBuilder *dibuilder,
76 uint64_t size_in_bits, uint64_t align_in_bits, ZigLLVMDIType *elem_type,
77 int elem_count);
78
79ZigLLVMDIEnumerator *ZigLLVMCreateDebugEnumerator(ZigLLVMDIBuilder *dibuilder, const char *name, int64_t val);
80
81ZigLLVMDIType *ZigLLVMCreateDebugEnumerationType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIScope *scope,
82 const char *name, ZigLLVMDIFile *file, unsigned line_number, uint64_t size_in_bits,
83 uint64_t align_in_bits, ZigLLVMDIEnumerator **enumerator_array, int enumerator_array_len,
84 ZigLLVMDIType *underlying_type, const char *unique_id);
85
86ZigLLVMDIType *ZigLLVMCreateDebugStructType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIScope *scope,
87 const char *name, ZigLLVMDIFile *file, unsigned line_number, uint64_t size_in_bits,
88 uint64_t align_in_bits, unsigned flags, ZigLLVMDIType *derived_from,
89 ZigLLVMDIType **types_array, int types_array_len, unsigned run_time_lang, ZigLLVMDIType *vtable_holder,
90 const char *unique_id);
91
92ZigLLVMDIType *ZigLLVMCreateDebugUnionType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIScope *scope,
93 const char *name, ZigLLVMDIFile *file, unsigned line_number, uint64_t size_in_bits,
94 uint64_t align_in_bits, unsigned flags, ZigLLVMDIType **types_array, int types_array_len,
95 unsigned run_time_lang, const char *unique_id);
96
97ZigLLVMDIType *ZigLLVMCreateDebugMemberType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIScope *scope,
98 const char *name, ZigLLVMDIFile *file, unsigned line, uint64_t size_in_bits,
99 uint64_t align_in_bits, uint64_t offset_in_bits, unsigned flags, ZigLLVMDIType *type);
100
101ZigLLVMDIType *ZigLLVMCreateReplaceableCompositeType(ZigLLVMDIBuilder *dibuilder, unsigned tag,
102 const char *name, ZigLLVMDIScope *scope, ZigLLVMDIFile *file, unsigned line);
103
104ZigLLVMDIType *ZigLLVMCreateDebugForwardDeclType(ZigLLVMDIBuilder *dibuilder, unsigned tag,
105 const char *name, ZigLLVMDIScope *scope, ZigLLVMDIFile *file, unsigned line);
106
107void ZigLLVMReplaceTemporary(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *type,
108 ZigLLVMDIType *replacement);
109
110void ZigLLVMReplaceDebugArrays(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *type,
111 ZigLLVMDIType **types_array, int types_array_len);
112
113ZigLLVMDIType *ZigLLVMCreateSubroutineType(ZigLLVMDIBuilder *dibuilder_wrapped,
114 ZigLLVMDIType **types_array, int types_array_len, unsigned flags);
115
116unsigned ZigLLVMEncoding_DW_ATE_unsigned(void);
117unsigned ZigLLVMEncoding_DW_ATE_signed(void);
118unsigned ZigLLVMEncoding_DW_ATE_float(void);
119unsigned ZigLLVMEncoding_DW_ATE_boolean(void);
120unsigned ZigLLVMEncoding_DW_ATE_unsigned_char(void);
121unsigned ZigLLVMEncoding_DW_ATE_signed_char(void);
122unsigned ZigLLVMLang_DW_LANG_C99(void);
123unsigned ZigLLVMTag_DW_variable(void);
124unsigned ZigLLVMTag_DW_structure_type(void);
125unsigned ZigLLVMTag_DW_union_type(void);
126
127ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);
128void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);
129void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module);
130
131void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column, ZigLLVMDIScope *scope);
132void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder);
133
134ZigLLVMDIScope *ZigLLVMLexicalBlockToScope(ZigLLVMDILexicalBlock *lexical_block);
135ZigLLVMDIScope *ZigLLVMCompileUnitToScope(ZigLLVMDICompileUnit *compile_unit);
136ZigLLVMDIScope *ZigLLVMFileToScope(ZigLLVMDIFile *difile);
137ZigLLVMDIScope *ZigLLVMSubprogramToScope(ZigLLVMDISubprogram *subprogram);
138ZigLLVMDIScope *ZigLLVMTypeToScope(ZigLLVMDIType *type);
139
140ZigLLVMDILocalVariable *ZigLLVMCreateAutoVariable(ZigLLVMDIBuilder *dbuilder,
141 ZigLLVMDIScope *scope, const char *name, ZigLLVMDIFile *file, unsigned line_no,
142 ZigLLVMDIType *type, bool always_preserve, unsigned flags);
143
144ZigLLVMDIGlobalVariable *ZigLLVMCreateGlobalVariable(ZigLLVMDIBuilder *dbuilder,
145 ZigLLVMDIScope *scope, const char *name, const char *linkage_name, ZigLLVMDIFile *file,
146 unsigned line_no, ZigLLVMDIType *di_type, bool is_local_to_unit);
147
148ZigLLVMDILocalVariable *ZigLLVMCreateParameterVariable(ZigLLVMDIBuilder *dbuilder,
149 ZigLLVMDIScope *scope, const char *name, ZigLLVMDIFile *file, unsigned line_no,
150 ZigLLVMDIType *type, bool always_preserve, unsigned flags, unsigned arg_no);
151
152ZigLLVMDILexicalBlock *ZigLLVMCreateLexicalBlock(ZigLLVMDIBuilder *dbuilder, ZigLLVMDIScope *scope,
153 ZigLLVMDIFile *file, unsigned line, unsigned col);
154
155ZigLLVMDICompileUnit *ZigLLVMCreateCompileUnit(ZigLLVMDIBuilder *dibuilder,
156 unsigned lang, ZigLLVMDIFile *difile, const char *producer,
157 bool is_optimized, const char *flags, unsigned runtime_version, const char *split_name,
158 uint64_t dwo_id, bool emit_debug_info);
159
160ZigLLVMDIFile *ZigLLVMCreateFile(ZigLLVMDIBuilder *dibuilder, const char *filename, const char *directory);
161
162ZigLLVMDISubprogram *ZigLLVMCreateFunction(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIScope *scope,
163 const char *name, const char *linkage_name, ZigLLVMDIFile *file, unsigned lineno,
164 ZigLLVMDIType *fn_di_type, bool is_local_to_unit, bool is_definition, unsigned scope_line,
165 unsigned flags, bool is_optimized, ZigLLVMDISubprogram *decl_subprogram);
166
167void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram);
168
169void ZigLLVMDIBuilderFinalize(ZigLLVMDIBuilder *dibuilder);
170
171LLVMValueRef ZigLLVMInsertDeclareAtEnd(ZigLLVMDIBuilder *dibuilder, LLVMValueRef storage,
172 ZigLLVMDILocalVariable *var_info, ZigLLVMDILocation *debug_loc, LLVMBasicBlockRef basic_block_ref);
173LLVMValueRef ZigLLVMInsertDeclare(ZigLLVMDIBuilder *dibuilder, LLVMValueRef storage,
174 ZigLLVMDILocalVariable *var_info, ZigLLVMDILocation *debug_loc, LLVMValueRef insert_before_instr);
175ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, ZigLLVMDIScope *scope);
176
177void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state);
178
179void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value);
180void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn);
181
182void ZigLLVMParseCommandLineOptions(int argc, const char *const *argv);
183
184
185// copied from include/llvm/ADT/Triple.h
186
187enum ZigLLVM_ArchType {
188 ZigLLVM_UnknownArch,
189
190 ZigLLVM_arm, // ARM (little endian): arm, armv.*, xscale
191 ZigLLVM_armeb, // ARM (big endian): armeb
192 ZigLLVM_aarch64, // AArch64 (little endian): aarch64
193 ZigLLVM_aarch64_be, // AArch64 (big endian): aarch64_be
194 ZigLLVM_arc, // ARC: Synopsys ARC
195 ZigLLVM_avr, // AVR: Atmel AVR microcontroller
196 ZigLLVM_bpfel, // eBPF or extended BPF or 64-bit BPF (little endian)
197 ZigLLVM_bpfeb, // eBPF or extended BPF or 64-bit BPF (big endian)
198 ZigLLVM_hexagon, // Hexagon: hexagon
199 ZigLLVM_mips, // MIPS: mips, mipsallegrex
200 ZigLLVM_mipsel, // MIPSEL: mipsel, mipsallegrexel
201 ZigLLVM_mips64, // MIPS64: mips64
202 ZigLLVM_mips64el, // MIPS64EL: mips64el
203 ZigLLVM_msp430, // MSP430: msp430
204 ZigLLVM_nios2, // NIOSII: nios2
205 ZigLLVM_ppc, // PPC: powerpc
206 ZigLLVM_ppc64, // PPC64: powerpc64, ppu
207 ZigLLVM_ppc64le, // PPC64LE: powerpc64le
208 ZigLLVM_r600, // R600: AMD GPUs HD2XXX - HD6XXX
209 ZigLLVM_amdgcn, // AMDGCN: AMD GCN GPUs
210 ZigLLVM_riscv32, // RISC-V (32-bit): riscv32
211 ZigLLVM_riscv64, // RISC-V (64-bit): riscv64
212 ZigLLVM_sparc, // Sparc: sparc
213 ZigLLVM_sparcv9, // Sparcv9: Sparcv9
214 ZigLLVM_sparcel, // Sparc: (endianness = little). NB: 'Sparcle' is a CPU variant
215 ZigLLVM_systemz, // SystemZ: s390x
216 ZigLLVM_tce, // TCE (http://tce.cs.tut.fi/): tce
217 ZigLLVM_tcele, // TCE little endian (http://tce.cs.tut.fi/): tcele
218 ZigLLVM_thumb, // Thumb (little endian): thumb, thumbv.*
219 ZigLLVM_thumbeb, // Thumb (big endian): thumbeb
220 ZigLLVM_x86, // X86: i[3-9]86
221 ZigLLVM_x86_64, // X86-64: amd64, x86_64
222 ZigLLVM_xcore, // XCore: xcore
223 ZigLLVM_nvptx, // NVPTX: 32-bit
224 ZigLLVM_nvptx64, // NVPTX: 64-bit
225 ZigLLVM_le32, // le32: generic little-endian 32-bit CPU (PNaCl)
226 ZigLLVM_le64, // le64: generic little-endian 64-bit CPU (PNaCl)
227 ZigLLVM_amdil, // AMDIL
228 ZigLLVM_amdil64, // AMDIL with 64-bit pointers
229 ZigLLVM_hsail, // AMD HSAIL
230 ZigLLVM_hsail64, // AMD HSAIL with 64-bit pointers
231 ZigLLVM_spir, // SPIR: standard portable IR for OpenCL 32-bit version
232 ZigLLVM_spir64, // SPIR: standard portable IR for OpenCL 64-bit version
233 ZigLLVM_kalimba, // Kalimba: generic kalimba
234 ZigLLVM_shave, // SHAVE: Movidius vector VLIW processors
235 ZigLLVM_lanai, // Lanai: Lanai 32-bit
236 ZigLLVM_wasm32, // WebAssembly with 32-bit pointers
237 ZigLLVM_wasm64, // WebAssembly with 64-bit pointers
238 ZigLLVM_renderscript32, // 32-bit RenderScript
239 ZigLLVM_renderscript64, // 64-bit RenderScript
240
241 ZigLLVM_LastArchType = ZigLLVM_renderscript64
242};
243
244enum ZigLLVM_SubArchType {
245 ZigLLVM_NoSubArch,
246
247 ZigLLVM_ARMSubArch_v8_3a,
248 ZigLLVM_ARMSubArch_v8_2a,
249 ZigLLVM_ARMSubArch_v8_1a,
250 ZigLLVM_ARMSubArch_v8,
251 ZigLLVM_ARMSubArch_v8r,
252 ZigLLVM_ARMSubArch_v8m_baseline,
253 ZigLLVM_ARMSubArch_v8m_mainline,
254 ZigLLVM_ARMSubArch_v7,
255 ZigLLVM_ARMSubArch_v7em,
256 ZigLLVM_ARMSubArch_v7m,
257 ZigLLVM_ARMSubArch_v7s,
258 ZigLLVM_ARMSubArch_v7k,
259 ZigLLVM_ARMSubArch_v7ve,
260 ZigLLVM_ARMSubArch_v6,
261 ZigLLVM_ARMSubArch_v6m,
262 ZigLLVM_ARMSubArch_v6k,
263 ZigLLVM_ARMSubArch_v6t2,
264 ZigLLVM_ARMSubArch_v5,
265 ZigLLVM_ARMSubArch_v5te,
266 ZigLLVM_ARMSubArch_v4t,
267
268 ZigLLVM_KalimbaSubArch_v3,
269 ZigLLVM_KalimbaSubArch_v4,
270 ZigLLVM_KalimbaSubArch_v5,
271};
272
273enum ZigLLVM_VendorType {
274 ZigLLVM_UnknownVendor,
275
276 ZigLLVM_Apple,
277 ZigLLVM_PC,
278 ZigLLVM_SCEI,
279 ZigLLVM_BGP,
280 ZigLLVM_BGQ,
281 ZigLLVM_Freescale,
282 ZigLLVM_IBM,
283 ZigLLVM_ImaginationTechnologies,
284 ZigLLVM_MipsTechnologies,
285 ZigLLVM_NVIDIA,
286 ZigLLVM_CSR,
287 ZigLLVM_Myriad,
288 ZigLLVM_AMD,
289 ZigLLVM_Mesa,
290 ZigLLVM_SUSE,
291
292 ZigLLVM_LastVendorType = ZigLLVM_SUSE
293};
294
295enum ZigLLVM_OSType {
296 ZigLLVM_UnknownOS,
297
298 ZigLLVM_Ananas,
299 ZigLLVM_CloudABI,
300 ZigLLVM_Darwin,
301 ZigLLVM_DragonFly,
302 ZigLLVM_FreeBSD,
303 ZigLLVM_Fuchsia,
304 ZigLLVM_IOS,
305 ZigLLVM_KFreeBSD,
306 ZigLLVM_Linux,
307 ZigLLVM_Lv2, // PS3
308 ZigLLVM_MacOSX,
309 ZigLLVM_NetBSD,
310 ZigLLVM_OpenBSD,
311 ZigLLVM_Solaris,
312 ZigLLVM_Win32,
313 ZigLLVM_Haiku,
314 ZigLLVM_Minix,
315 ZigLLVM_RTEMS,
316 ZigLLVM_NaCl, // Native Client
317 ZigLLVM_CNK, // BG/P Compute-Node Kernel
318 ZigLLVM_Bitrig,
319 ZigLLVM_AIX,
320 ZigLLVM_CUDA, // NVIDIA CUDA
321 ZigLLVM_NVCL, // NVIDIA OpenCL
322 ZigLLVM_AMDHSA, // AMD HSA Runtime
323 ZigLLVM_PS4,
324 ZigLLVM_ELFIAMCU,
325 ZigLLVM_TvOS, // Apple tvOS
326 ZigLLVM_WatchOS, // Apple watchOS
327 ZigLLVM_Mesa3D,
328 ZigLLVM_Contiki,
329
330 ZigLLVM_LastOSType = ZigLLVM_Contiki
331};
332
333enum ZigLLVM_EnvironmentType {
334 ZigLLVM_UnknownEnvironment,
335
336 ZigLLVM_GNU,
337 ZigLLVM_GNUABIN32,
338 ZigLLVM_GNUABI64,
339 ZigLLVM_GNUEABI,
340 ZigLLVM_GNUEABIHF,
341 ZigLLVM_GNUX32,
342 ZigLLVM_CODE16,
343 ZigLLVM_EABI,
344 ZigLLVM_EABIHF,
345 ZigLLVM_Android,
346 ZigLLVM_Musl,
347 ZigLLVM_MuslEABI,
348 ZigLLVM_MuslEABIHF,
349
350 ZigLLVM_MSVC,
351 ZigLLVM_Itanium,
352 ZigLLVM_Cygnus,
353 ZigLLVM_AMDOpenCL,
354 ZigLLVM_CoreCLR,
355 ZigLLVM_OpenCL,
356 ZigLLVM_Simulator, // Simulator variants of other systems, e.g., Apple's iOS
357
358 ZigLLVM_LastEnvironmentType = ZigLLVM_Simulator
359};
360
361enum ZigLLVM_ObjectFormatType {
362 ZigLLVM_UnknownObjectFormat,
363
364 ZigLLVM_COFF,
365 ZigLLVM_ELF,
366 ZigLLVM_MachO,
367 ZigLLVM_Wasm,
368};
369
370const char *ZigLLVMGetArchTypeName(ZigLLVM_ArchType arch);
371const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch);
372const char *ZigLLVMGetVendorTypeName(ZigLLVM_VendorType vendor);
373const char *ZigLLVMGetOSTypeName(ZigLLVM_OSType os);
374const char *ZigLLVMGetEnvironmentTypeName(ZigLLVM_EnvironmentType env_type);
375
376/*
377 * This stuff is not LLVM API but it depends on the LLVM C++ API so we put it here.
378 */
379struct Buf;
380
381bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag);
382
383void ZigLLVMGetNativeTarget(ZigLLVM_ArchType *arch_type, ZigLLVM_SubArchType *sub_arch_type,
384 ZigLLVM_VendorType *vendor_type, ZigLLVM_OSType *os_type, ZigLLVM_EnvironmentType *environ_type,
385 ZigLLVM_ObjectFormatType *oformat);
386
387#endif
std/array_list.zig+3-2
......@@ -1,6 +1,7 @@
1const debug = @import("debug.zig");
1const std = @import("index.zig");
2const debug = std.debug;
23const assert = debug.assert;
3const mem = @import("mem.zig");
4const mem = std.mem;
45const Allocator = mem.Allocator;
56
67pub fn ArrayList(comptime T: type) -> type {
std/base64.zig+3-2
......@@ -1,5 +1,6 @@
1const assert = @import("debug.zig").assert;
2const mem = @import("mem.zig");
1const std = @import("index.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
34
45pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
56pub const standard_pad_char = '=';
std/buffer.zig+5-4
......@@ -1,10 +1,11 @@
1const debug = @import("debug.zig");
2const mem = @import("mem.zig");
1const std = @import("index.zig");
2const debug = std.debug;
3const mem = std.mem;
34const Allocator = mem.Allocator;
45const assert = debug.assert;
5const ArrayList = @import("array_list.zig").ArrayList;
6const ArrayList = std.ArrayList;
67
7const fmt = @import("fmt/index.zig");
8const fmt = std.fmt;
89
910/// A buffer that allocates memory and maintains a null byte at the end.
1011pub const Buffer = struct {
std/build.zig+7
......@@ -784,6 +784,13 @@ const Target = union(enum) {
784784 };
785785 }
786786
787 pub fn libFileExt(self: &const Target) -> []const u8 {
788 return switch (self.getOs()) {
789 builtin.Os.windows => ".lib",
790 else => ".a",
791 };
792 }
793
787794 pub fn getOs(self: &const Target) -> builtin.Os {
788795 return switch (*self) {
789796 Target.Native => builtin.os,
std/cstr.zig+57-2
......@@ -1,5 +1,6 @@
1const debug = @import("debug.zig");
2const mem = @import("mem.zig");
1const std = @import("index.zig");
2const debug = std.debug;
3const mem = std.mem;
34const assert = debug.assert;
45
56pub fn len(ptr: &const u8) -> usize {
......@@ -47,3 +48,57 @@ pub fn addNullByte(allocator: &mem.Allocator, slice: []const u8) -> %[]u8 {
4748 result[slice.len] = 0;
4849 return result;
4950}
51
52pub const NullTerminated2DArray = struct {
53 allocator: &mem.Allocator,
54 byte_count: usize,
55 ptr: ?&?&u8,
56
57 /// Takes N lists of strings, concatenates the lists together, and adds a null terminator
58 /// Caller must deinit result
59 pub fn fromSlices(allocator: &mem.Allocator, slices: []const []const []const u8) -> %NullTerminated2DArray {
60 var new_len: usize = 1; // 1 for the list null
61 var byte_count: usize = 0;
62 for (slices) |slice| {
63 new_len += slice.len;
64 for (slice) |inner| {
65 byte_count += inner.len;
66 }
67 byte_count += slice.len; // for the null terminators of inner
68 }
69
70 const index_size = @sizeOf(usize) * new_len; // size of the ptrs
71 byte_count += index_size;
72
73 const buf = %return allocator.alignedAlloc(u8, @alignOf(?&u8), byte_count);
74 %defer allocator.free(buf);
75
76 var write_index = index_size;
77 const index_buf = ([]?&u8)(buf);
78
79 var i: usize = 0;
80 for (slices) |slice| {
81 for (slice) |inner| {
82 index_buf[i] = &buf[write_index];
83 i += 1;
84 mem.copy(u8, buf[write_index..], inner);
85 write_index += inner.len;
86 buf[write_index] = 0;
87 write_index += 1;
88 }
89 }
90 index_buf[i] = null;
91
92 return NullTerminated2DArray {
93 .allocator = allocator,
94 .byte_count = byte_count,
95 .ptr = @ptrCast(?&?&u8, buf.ptr),
96 };
97 }
98
99 pub fn deinit(self: &NullTerminated2DArray) {
100 const buf = @ptrCast(&u8, self.ptr);
101 self.allocator.free(buf[0..self.byte_count]);
102 }
103};
104
std/debug.zig deleted-1050
......@@ -1,1050 +0,0 @@
1const std = @import("index.zig");
2const math = std.math;
3const mem = std.mem;
4const io = std.io;
5const os = std.os;
6const elf = @import("elf.zig");
7const DW = @import("dwarf.zig");
8const ArrayList = std.ArrayList;
9const builtin = @import("builtin");
10
11error MissingDebugInfo;
12error InvalidDebugInfo;
13error UnsupportedDebugInfo;
14
15
16/// Tries to write to stderr, unbuffered, and ignores any error returned.
17/// Does not append a newline.
18/// TODO atomic/multithread support
19var stderr_file: io.File = undefined;
20var stderr_file_out_stream: io.FileOutStream = undefined;
21var stderr_stream: ?&io.OutStream = null;
22pub fn warn(comptime fmt: []const u8, args: ...) {
23 const stderr = getStderrStream() %% return;
24 stderr.print(fmt, args) %% return;
25}
26fn getStderrStream() -> %&io.OutStream {
27 if (stderr_stream) |st| {
28 return st;
29 } else {
30 stderr_file = %return io.getStdErr();
31 stderr_file_out_stream = io.FileOutStream.init(&stderr_file);
32 const st = &stderr_file_out_stream.stream;
33 stderr_stream = st;
34 return st;
35 }
36}
37
38/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
39pub fn dumpStackTrace() {
40 const stderr = getStderrStream() %% return;
41 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) %% return;
42}
43
44/// This function invokes undefined behavior when `ok` is `false`.
45/// In Debug and ReleaseSafe modes, calls to this function are always
46/// generated, and the `unreachable` statement triggers a panic.
47/// In ReleaseFast and ReleaseSmall modes, calls to this function can be
48/// optimized away.
49pub fn assert(ok: bool) {
50 if (!ok) {
51 // In ReleaseFast test mode, we still want assert(false) to crash, so
52 // we insert an explicit call to @panic instead of unreachable.
53 // TODO we should use `assertOrPanic` in tests and remove this logic.
54 if (builtin.is_test) {
55 @panic("assertion failure");
56 } else {
57 unreachable; // assertion failure
58 }
59 }
60}
61
62/// Call this function when you want to panic if the condition is not true.
63/// If `ok` is `false`, this function will panic in every release mode.
64pub fn assertOrPanic(ok: bool) {
65 if (!ok) {
66 @panic("assertion failure");
67 }
68}
69
70var panicking = false;
71/// This is the default panic implementation.
72pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
73 // TODO an intrinsic that labels this as unlikely to be reached
74
75 // TODO
76 // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }
77 if (panicking) {
78 // Panicked during a panic.
79 // TODO detect if a different thread caused the panic, because in that case
80 // we would want to return here instead of calling abort, so that the thread
81 // which first called panic can finish printing a stack trace.
82 os.abort();
83 } else {
84 panicking = true;
85 }
86
87 const stderr = getStderrStream() %% os.abort();
88 stderr.print(format ++ "\n", args) %% os.abort();
89 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) %% os.abort();
90
91 os.abort();
92}
93
94const GREEN = "\x1b[32;1m";
95const WHITE = "\x1b[37;1m";
96const DIM = "\x1b[2m";
97const RESET = "\x1b[0m";
98
99error PathNotFound;
100error InvalidDebugInfo;
101
102pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,
103 ignore_frame_count: usize) -> %void
104{
105 switch (builtin.object_format) {
106 builtin.ObjectFormat.elf => {
107 var stack_trace = ElfStackTrace {
108 .self_exe_file = undefined,
109 .elf = undefined,
110 .debug_info = undefined,
111 .debug_abbrev = undefined,
112 .debug_str = undefined,
113 .debug_line = undefined,
114 .debug_ranges = null,
115 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
116 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
117 };
118 const st = &stack_trace;
119 st.self_exe_file = %return os.openSelfExe();
120 defer st.self_exe_file.close();
121
122 %return st.elf.openFile(allocator, &st.self_exe_file);
123 defer st.elf.close();
124
125 st.debug_info = (%return st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
126 st.debug_abbrev = (%return st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
127 st.debug_str = (%return st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo;
128 st.debug_line = (%return st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
129 st.debug_ranges = (%return st.elf.findSection(".debug_ranges"));
130 %return scanAllCompileUnits(st);
131
132 var ignored_count: usize = 0;
133
134 var fp = @ptrToInt(@frameAddress());
135 while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
136 if (ignored_count < ignore_frame_count) {
137 ignored_count += 1;
138 continue;
139 }
140
141 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
142
143 // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
144 // at compile time. I'll call it issue #313
145 const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
146
147 const compile_unit = findCompileUnit(st, return_address) %% {
148 %return out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
149 return_address);
150 continue;
151 };
152 const compile_unit_name = %return compile_unit.die.getAttrString(st, DW.AT_name);
153 if (getLineNumberInfo(st, compile_unit, usize(return_address) - 1)) |line_info| {
154 defer line_info.deinit();
155 %return out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
156 DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
157 line_info.file_name, line_info.line, line_info.column,
158 return_address, compile_unit_name);
159 if (printLineFromFile(st.allocator(), out_stream, line_info)) {
160 if (line_info.column == 0) {
161 %return out_stream.write("\n");
162 } else {
163 {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
164 %return out_stream.writeByte(' ');
165 }}
166 %return out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
167 }
168 } else |err| switch (err) {
169 error.EndOfFile, error.PathNotFound => {},
170 else => return err,
171 }
172 } else |err| switch (err) {
173 error.MissingDebugInfo, error.InvalidDebugInfo => {
174 %return out_stream.print(ptr_hex ++ " in ??? ({})\n",
175 return_address, compile_unit_name);
176 },
177 else => return err,
178 }
179 }
180 },
181 builtin.ObjectFormat.coff => {
182 %return out_stream.write("(stack trace unavailable for COFF object format)\n");
183 },
184 builtin.ObjectFormat.macho => {
185 %return out_stream.write("(stack trace unavailable for Mach-O object format)\n");
186 },
187 builtin.ObjectFormat.wasm => {
188 %return out_stream.write("(stack trace unavailable for WASM object format)\n");
189 },
190 builtin.ObjectFormat.unknown => {
191 %return out_stream.write("(stack trace unavailable for unknown object format)\n");
192 },
193 }
194}
195
196fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_info: &const LineInfo) -> %void {
197 var f = %return io.File.openRead(line_info.file_name, allocator);
198 defer f.close();
199 // TODO fstat and make sure that the file has the correct size
200
201 var buf: [os.page_size]u8 = undefined;
202 var line: usize = 1;
203 var column: usize = 1;
204 var abs_index: usize = 0;
205 while (true) {
206 const amt_read = %return f.read(buf[0..]);
207 const slice = buf[0..amt_read];
208
209 for (slice) |byte| {
210 if (line == line_info.line) {
211 %return out_stream.writeByte(byte);
212 if (byte == '\n') {
213 return;
214 }
215 }
216 if (byte == '\n') {
217 line += 1;
218 column = 1;
219 } else {
220 column += 1;
221 }
222 }
223
224 if (amt_read < buf.len)
225 return error.EndOfFile;
226 }
227}
228
229const ElfStackTrace = struct {
230 self_exe_file: io.File,
231 elf: elf.Elf,
232 debug_info: &elf.SectionHeader,
233 debug_abbrev: &elf.SectionHeader,
234 debug_str: &elf.SectionHeader,
235 debug_line: &elf.SectionHeader,
236 debug_ranges: ?&elf.SectionHeader,
237 abbrev_table_list: ArrayList(AbbrevTableHeader),
238 compile_unit_list: ArrayList(CompileUnit),
239
240 pub fn allocator(self: &const ElfStackTrace) -> &mem.Allocator {
241 return self.abbrev_table_list.allocator;
242 }
243
244 pub fn readString(self: &ElfStackTrace) -> %[]u8 {
245 var in_file_stream = io.FileInStream.init(&self.self_exe_file);
246 const in_stream = &in_file_stream.stream;
247 return readStringRaw(self.allocator(), in_stream);
248 }
249};
250
251const PcRange = struct {
252 start: u64,
253 end: u64,
254};
255
256const CompileUnit = struct {
257 version: u16,
258 is_64: bool,
259 die: &Die,
260 index: usize,
261 pc_range: ?PcRange,
262};
263
264const AbbrevTable = ArrayList(AbbrevTableEntry);
265
266const AbbrevTableHeader = struct {
267 // offset from .debug_abbrev
268 offset: u64,
269 table: AbbrevTable,
270};
271
272const AbbrevTableEntry = struct {
273 has_children: bool,
274 abbrev_code: u64,
275 tag_id: u64,
276 attrs: ArrayList(AbbrevAttr),
277};
278
279const AbbrevAttr = struct {
280 attr_id: u64,
281 form_id: u64,
282};
283
284const FormValue = union(enum) {
285 Address: u64,
286 Block: []u8,
287 Const: Constant,
288 ExprLoc: []u8,
289 Flag: bool,
290 SecOffset: u64,
291 Ref: []u8,
292 RefAddr: u64,
293 RefSig8: u64,
294 String: []u8,
295 StrPtr: u64,
296};
297
298const Constant = struct {
299 payload: []u8,
300 signed: bool,
301
302 fn asUnsignedLe(self: &const Constant) -> %u64 {
303 if (self.payload.len > @sizeOf(u64))
304 return error.InvalidDebugInfo;
305 if (self.signed)
306 return error.InvalidDebugInfo;
307 return mem.readInt(self.payload, u64, builtin.Endian.Little);
308 }
309};
310
311const Die = struct {
312 tag_id: u64,
313 has_children: bool,
314 attrs: ArrayList(Attr),
315
316 const Attr = struct {
317 id: u64,
318 value: FormValue,
319 };
320
321 fn getAttr(self: &const Die, id: u64) -> ?&const FormValue {
322 for (self.attrs.toSliceConst()) |*attr| {
323 if (attr.id == id)
324 return &attr.value;
325 }
326 return null;
327 }
328
329 fn getAttrAddr(self: &const Die, id: u64) -> %u64 {
330 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
331 return switch (*form_value) {
332 FormValue.Address => |value| value,
333 else => error.InvalidDebugInfo,
334 };
335 }
336
337 fn getAttrSecOffset(self: &const Die, id: u64) -> %u64 {
338 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
339 return switch (*form_value) {
340 FormValue.Const => |value| value.asUnsignedLe(),
341 FormValue.SecOffset => |value| value,
342 else => error.InvalidDebugInfo,
343 };
344 }
345
346 fn getAttrUnsignedLe(self: &const Die, id: u64) -> %u64 {
347 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
348 return switch (*form_value) {
349 FormValue.Const => |value| value.asUnsignedLe(),
350 else => error.InvalidDebugInfo,
351 };
352 }
353
354 fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) -> %[]u8 {
355 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
356 return switch (*form_value) {
357 FormValue.String => |value| value,
358 FormValue.StrPtr => |offset| getString(st, offset),
359 else => error.InvalidDebugInfo,
360 };
361 }
362};
363
364const FileEntry = struct {
365 file_name: []const u8,
366 dir_index: usize,
367 mtime: usize,
368 len_bytes: usize,
369};
370
371const LineInfo = struct {
372 line: usize,
373 column: usize,
374 file_name: []u8,
375 allocator: &mem.Allocator,
376
377 fn deinit(self: &const LineInfo) {
378 self.allocator.free(self.file_name);
379 }
380};
381
382const LineNumberProgram = struct {
383 address: usize,
384 file: usize,
385 line: isize,
386 column: usize,
387 is_stmt: bool,
388 basic_block: bool,
389 end_sequence: bool,
390
391 target_address: usize,
392 include_dirs: []const []const u8,
393 file_entries: &ArrayList(FileEntry),
394
395 prev_address: usize,
396 prev_file: usize,
397 prev_line: isize,
398 prev_column: usize,
399 prev_is_stmt: bool,
400 prev_basic_block: bool,
401 prev_end_sequence: bool,
402
403 pub fn init(is_stmt: bool, include_dirs: []const []const u8,
404 file_entries: &ArrayList(FileEntry), target_address: usize) -> LineNumberProgram
405 {
406 return LineNumberProgram {
407 .address = 0,
408 .file = 1,
409 .line = 1,
410 .column = 0,
411 .is_stmt = is_stmt,
412 .basic_block = false,
413 .end_sequence = false,
414 .include_dirs = include_dirs,
415 .file_entries = file_entries,
416 .target_address = target_address,
417 .prev_address = 0,
418 .prev_file = undefined,
419 .prev_line = undefined,
420 .prev_column = undefined,
421 .prev_is_stmt = undefined,
422 .prev_basic_block = undefined,
423 .prev_end_sequence = undefined,
424 };
425 }
426
427 pub fn checkLineMatch(self: &LineNumberProgram) -> %?LineInfo {
428 if (self.target_address >= self.prev_address and self.target_address < self.address) {
429 const file_entry = if (self.prev_file == 0) {
430 return error.MissingDebugInfo;
431 } else if (self.prev_file - 1 >= self.file_entries.len) {
432 return error.InvalidDebugInfo;
433 } else &self.file_entries.items[self.prev_file - 1];
434
435 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
436 return error.InvalidDebugInfo;
437 } else self.include_dirs[file_entry.dir_index];
438 const file_name = %return os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
439 %defer self.file_entries.allocator.free(file_name);
440 return LineInfo {
441 .line = if (self.prev_line >= 0) usize(self.prev_line) else 0,
442 .column = self.prev_column,
443 .file_name = file_name,
444 .allocator = self.file_entries.allocator,
445 };
446 }
447
448 self.prev_address = self.address;
449 self.prev_file = self.file;
450 self.prev_line = self.line;
451 self.prev_column = self.column;
452 self.prev_is_stmt = self.is_stmt;
453 self.prev_basic_block = self.basic_block;
454 self.prev_end_sequence = self.end_sequence;
455 return null;
456 }
457};
458
459fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) -> %[]u8 {
460 var buf = ArrayList(u8).init(allocator);
461 while (true) {
462 const byte = %return in_stream.readByte();
463 if (byte == 0)
464 break;
465 %return buf.append(byte);
466 }
467 return buf.toSlice();
468}
469
470fn getString(st: &ElfStackTrace, offset: u64) -> %[]u8 {
471 const pos = st.debug_str.offset + offset;
472 %return st.self_exe_file.seekTo(pos);
473 return st.readString();
474}
475
476fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %[]u8 {
477 const buf = %return global_allocator.alloc(u8, size);
478 %defer global_allocator.free(buf);
479 if ((%return in_stream.read(buf)) < size) return error.EndOfFile;
480 return buf;
481}
482
483fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
484 const buf = %return readAllocBytes(allocator, in_stream, size);
485 return FormValue { .Block = buf };
486}
487
488fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
489 const block_len = %return in_stream.readVarInt(builtin.Endian.Little, usize, size);
490 return parseFormValueBlockLen(allocator, in_stream, block_len);
491}
492
493fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
494 return FormValue { .Const = Constant {
495 .signed = signed,
496 .payload = %return readAllocBytes(allocator, in_stream, size),
497 }};
498}
499
500fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) -> %u64 {
501 return if (is_64) %return in_stream.readIntLe(u64)
502 else u64(%return in_stream.readIntLe(u32)) ;
503}
504
505fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
506 return if (@sizeOf(usize) == 4) u64(%return in_stream.readIntLe(u32))
507 else if (@sizeOf(usize) == 8) %return in_stream.readIntLe(u64)
508 else unreachable;
509}
510
511fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
512 const buf = %return readAllocBytes(allocator, in_stream, size);
513 return FormValue { .Ref = buf };
514}
515
516fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) -> %FormValue {
517 const block_len = %return in_stream.readIntLe(T);
518 return parseFormValueRefLen(allocator, in_stream, block_len);
519}
520
521fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) -> %FormValue {
522 return switch (form_id) {
523 DW.FORM_addr => FormValue { .Address = %return parseFormValueTargetAddrSize(in_stream) },
524 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
525 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
526 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
527 DW.FORM_block => x: {
528 const block_len = %return readULeb128(in_stream);
529 return parseFormValueBlockLen(allocator, in_stream, block_len);
530 },
531 DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
532 DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
533 DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
534 DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
535 DW.FORM_udata, DW.FORM_sdata => {
536 const block_len = %return readULeb128(in_stream);
537 const signed = form_id == DW.FORM_sdata;
538 return parseFormValueConstant(allocator, in_stream, signed, block_len);
539 },
540 DW.FORM_exprloc => {
541 const size = %return readULeb128(in_stream);
542 const buf = %return readAllocBytes(allocator, in_stream, size);
543 return FormValue { .ExprLoc = buf };
544 },
545 DW.FORM_flag => FormValue { .Flag = (%return in_stream.readByte()) != 0 },
546 DW.FORM_flag_present => FormValue { .Flag = true },
547 DW.FORM_sec_offset => FormValue { .SecOffset = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
548
549 DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
550 DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
551 DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, u32),
552 DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
553 DW.FORM_ref_udata => {
554 const ref_len = %return readULeb128(in_stream);
555 return parseFormValueRefLen(allocator, in_stream, ref_len);
556 },
557
558 DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
559 DW.FORM_ref_sig8 => FormValue { .RefSig8 = %return in_stream.readIntLe(u64) },
560
561 DW.FORM_string => FormValue { .String = %return readStringRaw(allocator, in_stream) },
562 DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
563 DW.FORM_indirect => {
564 const child_form_id = %return readULeb128(in_stream);
565 return parseFormValue(allocator, in_stream, child_form_id, is_64);
566 },
567 else => error.InvalidDebugInfo,
568 };
569}
570
571fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {
572 const in_file = &st.self_exe_file;
573 var in_file_stream = io.FileInStream.init(in_file);
574 const in_stream = &in_file_stream.stream;
575 var result = AbbrevTable.init(st.allocator());
576 while (true) {
577 const abbrev_code = %return readULeb128(in_stream);
578 if (abbrev_code == 0)
579 return result;
580 %return result.append(AbbrevTableEntry {
581 .abbrev_code = abbrev_code,
582 .tag_id = %return readULeb128(in_stream),
583 .has_children = (%return in_stream.readByte()) == DW.CHILDREN_yes,
584 .attrs = ArrayList(AbbrevAttr).init(st.allocator()),
585 });
586 const attrs = &result.items[result.len - 1].attrs;
587
588 while (true) {
589 const attr_id = %return readULeb128(in_stream);
590 const form_id = %return readULeb128(in_stream);
591 if (attr_id == 0 and form_id == 0)
592 break;
593 %return attrs.append(AbbrevAttr {
594 .attr_id = attr_id,
595 .form_id = form_id,
596 });
597 }
598 }
599}
600
601/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
602/// seeks in the stream and parses it.
603fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) -> %&const AbbrevTable {
604 for (st.abbrev_table_list.toSlice()) |*header| {
605 if (header.offset == abbrev_offset) {
606 return &header.table;
607 }
608 }
609 %return st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
610 %return st.abbrev_table_list.append(AbbrevTableHeader {
611 .offset = abbrev_offset,
612 .table = %return parseAbbrevTable(st),
613 });
614 return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table;
615}
616
617fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) -> ?&const AbbrevTableEntry {
618 for (abbrev_table.toSliceConst()) |*table_entry| {
619 if (table_entry.abbrev_code == abbrev_code)
620 return table_entry;
621 }
622 return null;
623}
624
625fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -> %Die {
626 const in_file = &st.self_exe_file;
627 var in_file_stream = io.FileInStream.init(in_file);
628 const in_stream = &in_file_stream.stream;
629 const abbrev_code = %return readULeb128(in_stream);
630 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
631
632 var result = Die {
633 .tag_id = table_entry.tag_id,
634 .has_children = table_entry.has_children,
635 .attrs = ArrayList(Die.Attr).init(st.allocator()),
636 };
637 %return result.attrs.resize(table_entry.attrs.len);
638 for (table_entry.attrs.toSliceConst()) |attr, i| {
639 result.attrs.items[i] = Die.Attr {
640 .id = attr.attr_id,
641 .value = %return parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
642 };
643 }
644 return result;
645}
646
647fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) -> %LineInfo {
648 const compile_unit_cwd = %return compile_unit.die.getAttrString(st, DW.AT_comp_dir);
649
650 const in_file = &st.self_exe_file;
651 const debug_line_end = st.debug_line.offset + st.debug_line.size;
652 var this_offset = st.debug_line.offset;
653 var this_index: usize = 0;
654
655 var in_file_stream = io.FileInStream.init(in_file);
656 const in_stream = &in_file_stream.stream;
657
658 while (this_offset < debug_line_end) : (this_index += 1) {
659 %return in_file.seekTo(this_offset);
660
661 var is_64: bool = undefined;
662 const unit_length = %return readInitialLength(in_stream, &is_64);
663 if (unit_length == 0)
664 return error.MissingDebugInfo;
665 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
666
667 if (compile_unit.index != this_index) {
668 this_offset += next_offset;
669 continue;
670 }
671
672 const version = %return in_stream.readInt(st.elf.endian, u16);
673 if (version != 2) return error.InvalidDebugInfo;
674
675 const prologue_length = %return in_stream.readInt(st.elf.endian, u32);
676 const prog_start_offset = (%return in_file.getPos()) + prologue_length;
677
678 const minimum_instruction_length = %return in_stream.readByte();
679 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
680
681 const default_is_stmt = (%return in_stream.readByte()) != 0;
682 const line_base = %return in_stream.readByteSigned();
683
684 const line_range = %return in_stream.readByte();
685 if (line_range == 0)
686 return error.InvalidDebugInfo;
687
688 const opcode_base = %return in_stream.readByte();
689
690 const standard_opcode_lengths = %return st.allocator().alloc(u8, opcode_base - 1);
691
692 {var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {
693 standard_opcode_lengths[i] = %return in_stream.readByte();
694 }}
695
696 var include_directories = ArrayList([]u8).init(st.allocator());
697 %return include_directories.append(compile_unit_cwd);
698 while (true) {
699 const dir = %return st.readString();
700 if (dir.len == 0)
701 break;
702 %return include_directories.append(dir);
703 }
704
705 var file_entries = ArrayList(FileEntry).init(st.allocator());
706 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(),
707 &file_entries, target_address);
708
709 while (true) {
710 const file_name = %return st.readString();
711 if (file_name.len == 0)
712 break;
713 const dir_index = %return readULeb128(in_stream);
714 const mtime = %return readULeb128(in_stream);
715 const len_bytes = %return readULeb128(in_stream);
716 %return file_entries.append(FileEntry {
717 .file_name = file_name,
718 .dir_index = dir_index,
719 .mtime = mtime,
720 .len_bytes = len_bytes,
721 });
722 }
723
724 %return in_file.seekTo(prog_start_offset);
725
726 while (true) {
727 const opcode = %return in_stream.readByte();
728
729 var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
730 if (opcode == DW.LNS_extended_op) {
731 const op_size = %return readULeb128(in_stream);
732 if (op_size < 1)
733 return error.InvalidDebugInfo;
734 sub_op = %return in_stream.readByte();
735 switch (sub_op) {
736 DW.LNE_end_sequence => {
737 prog.end_sequence = true;
738 if (%return prog.checkLineMatch()) |info| return info;
739 return error.MissingDebugInfo;
740 },
741 DW.LNE_set_address => {
742 const addr = %return in_stream.readInt(st.elf.endian, usize);
743 prog.address = addr;
744 },
745 DW.LNE_define_file => {
746 const file_name = %return st.readString();
747 const dir_index = %return readULeb128(in_stream);
748 const mtime = %return readULeb128(in_stream);
749 const len_bytes = %return readULeb128(in_stream);
750 %return file_entries.append(FileEntry {
751 .file_name = file_name,
752 .dir_index = dir_index,
753 .mtime = mtime,
754 .len_bytes = len_bytes,
755 });
756 },
757 else => {
758 const fwd_amt = math.cast(isize, op_size - 1) %% return error.InvalidDebugInfo;
759 %return in_file.seekForward(fwd_amt);
760 },
761 }
762 } else if (opcode >= opcode_base) {
763 // special opcodes
764 const adjusted_opcode = opcode - opcode_base;
765 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
766 const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
767 prog.line += inc_line;
768 prog.address += inc_addr;
769 if (%return prog.checkLineMatch()) |info| return info;
770 prog.basic_block = false;
771 } else {
772 switch (opcode) {
773 DW.LNS_copy => {
774 if (%return prog.checkLineMatch()) |info| return info;
775 prog.basic_block = false;
776 },
777 DW.LNS_advance_pc => {
778 const arg = %return readULeb128(in_stream);
779 prog.address += arg * minimum_instruction_length;
780 },
781 DW.LNS_advance_line => {
782 const arg = %return readILeb128(in_stream);
783 prog.line += arg;
784 },
785 DW.LNS_set_file => {
786 const arg = %return readULeb128(in_stream);
787 prog.file = arg;
788 },
789 DW.LNS_set_column => {
790 const arg = %return readULeb128(in_stream);
791 prog.column = arg;
792 },
793 DW.LNS_negate_stmt => {
794 prog.is_stmt = !prog.is_stmt;
795 },
796 DW.LNS_set_basic_block => {
797 prog.basic_block = true;
798 },
799 DW.LNS_const_add_pc => {
800 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
801 prog.address += inc_addr;
802 },
803 DW.LNS_fixed_advance_pc => {
804 const arg = %return in_stream.readInt(st.elf.endian, u16);
805 prog.address += arg;
806 },
807 DW.LNS_set_prologue_end => {
808 },
809 else => {
810 if (opcode - 1 >= standard_opcode_lengths.len)
811 return error.InvalidDebugInfo;
812 const len_bytes = standard_opcode_lengths[opcode - 1];
813 %return in_file.seekForward(len_bytes);
814 },
815 }
816 }
817 }
818
819 this_offset += next_offset;
820 }
821
822 return error.MissingDebugInfo;
823}
824
825fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
826 const debug_info_end = st.debug_info.offset + st.debug_info.size;
827 var this_unit_offset = st.debug_info.offset;
828 var cu_index: usize = 0;
829
830 var in_file_stream = io.FileInStream.init(&st.self_exe_file);
831 const in_stream = &in_file_stream.stream;
832
833 while (this_unit_offset < debug_info_end) {
834 %return st.self_exe_file.seekTo(this_unit_offset);
835
836 var is_64: bool = undefined;
837 const unit_length = %return readInitialLength(in_stream, &is_64);
838 if (unit_length == 0)
839 return;
840 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
841
842 const version = %return in_stream.readInt(st.elf.endian, u16);
843 if (version < 2 or version > 5) return error.InvalidDebugInfo;
844
845 const debug_abbrev_offset =
846 if (is_64) %return in_stream.readInt(st.elf.endian, u64)
847 else %return in_stream.readInt(st.elf.endian, u32);
848
849 const address_size = %return in_stream.readByte();
850 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
851
852 const compile_unit_pos = %return st.self_exe_file.getPos();
853 const abbrev_table = %return getAbbrevTable(st, debug_abbrev_offset);
854
855 %return st.self_exe_file.seekTo(compile_unit_pos);
856
857 const compile_unit_die = %return st.allocator().create(Die);
858 *compile_unit_die = %return parseDie(st, abbrev_table, is_64);
859
860 if (compile_unit_die.tag_id != DW.TAG_compile_unit)
861 return error.InvalidDebugInfo;
862
863 const pc_range = x: {
864 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
865 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
866 const pc_end = switch (*high_pc_value) {
867 FormValue.Address => |value| value,
868 FormValue.Const => |value| b: {
869 const offset = %return value.asUnsignedLe();
870 break :b (low_pc + offset);
871 },
872 else => return error.InvalidDebugInfo,
873 };
874 break :x PcRange {
875 .start = low_pc,
876 .end = pc_end,
877 };
878 } else {
879 break :x null;
880 }
881 } else |err| {
882 if (err != error.MissingDebugInfo)
883 return err;
884 break :x null;
885 }
886 };
887
888 %return st.compile_unit_list.append(CompileUnit {
889 .version = version,
890 .is_64 = is_64,
891 .pc_range = pc_range,
892 .die = compile_unit_die,
893 .index = cu_index,
894 });
895
896 this_unit_offset += next_offset;
897 cu_index += 1;
898 }
899}
900
901fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> %&const CompileUnit {
902 var in_file_stream = io.FileInStream.init(&st.self_exe_file);
903 const in_stream = &in_file_stream.stream;
904 for (st.compile_unit_list.toSlice()) |*compile_unit| {
905 if (compile_unit.pc_range) |range| {
906 if (target_address >= range.start and target_address < range.end)
907 return compile_unit;
908 }
909 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
910 var base_address: usize = 0;
911 if (st.debug_ranges) |debug_ranges| {
912 %return st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset);
913 while (true) {
914 const begin_addr = %return in_stream.readIntLe(usize);
915 const end_addr = %return in_stream.readIntLe(usize);
916 if (begin_addr == 0 and end_addr == 0) {
917 break;
918 }
919 if (begin_addr == @maxValue(usize)) {
920 base_address = begin_addr;
921 continue;
922 }
923 if (target_address >= begin_addr and target_address < end_addr) {
924 return compile_unit;
925 }
926 }
927 }
928 } else |err| {
929 if (err != error.MissingDebugInfo)
930 return err;
931 continue;
932 }
933 }
934 return error.MissingDebugInfo;
935}
936
937fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 {
938 const first_32_bits = %return in_stream.readIntLe(u32);
939 *is_64 = (first_32_bits == 0xffffffff);
940 if (*is_64) {
941 return in_stream.readIntLe(u64);
942 } else {
943 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
944 return u64(first_32_bits);
945 }
946}
947
948fn readULeb128(in_stream: &io.InStream) -> %u64 {
949 var result: u64 = 0;
950 var shift: usize = 0;
951
952 while (true) {
953 const byte = %return in_stream.readByte();
954
955 var operand: u64 = undefined;
956
957 if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand))
958 return error.InvalidDebugInfo;
959
960 result |= operand;
961
962 if ((byte & 0b10000000) == 0)
963 return result;
964
965 shift += 7;
966 }
967}
968
969fn readILeb128(in_stream: &io.InStream) -> %i64 {
970 var result: i64 = 0;
971 var shift: usize = 0;
972
973 while (true) {
974 const byte = %return in_stream.readByte();
975
976 var operand: i64 = undefined;
977
978 if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand))
979 return error.InvalidDebugInfo;
980
981 result |= operand;
982 shift += 7;
983
984 if ((byte & 0b10000000) == 0) {
985 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0)
986 result |= -(i64(1) << u6(shift));
987 return result;
988 }
989 }
990}
991
992pub const global_allocator = &global_fixed_allocator.allocator;
993var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]);
994var global_allocator_mem: [100 * 1024]u8 = undefined;
995
996/// Allocator that fails after N allocations, useful for making sure out of
997/// memory conditions are handled correctly.
998pub const FailingAllocator = struct {
999 allocator: mem.Allocator,
1000 index: usize,
1001 fail_index: usize,
1002 internal_allocator: &mem.Allocator,
1003 allocated_bytes: usize,
1004
1005 pub fn init(allocator: &mem.Allocator, fail_index: usize) -> FailingAllocator {
1006 return FailingAllocator {
1007 .internal_allocator = allocator,
1008 .fail_index = fail_index,
1009 .index = 0,
1010 .allocated_bytes = 0,
1011 .allocator = mem.Allocator {
1012 .allocFn = alloc,
1013 .reallocFn = realloc,
1014 .freeFn = free,
1015 },
1016 };
1017 }
1018
1019 fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) -> %[]u8 {
1020 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
1021 if (self.index == self.fail_index) {
1022 return error.OutOfMemory;
1023 }
1024 self.index += 1;
1025 const result = %return self.internal_allocator.allocFn(self.internal_allocator, n, alignment);
1026 self.allocated_bytes += result.len;
1027 return result;
1028 }
1029
1030 fn realloc(allocator: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
1031 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
1032 if (new_size <= old_mem.len) {
1033 self.allocated_bytes -= old_mem.len - new_size;
1034 return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment);
1035 }
1036 if (self.index == self.fail_index) {
1037 return error.OutOfMemory;
1038 }
1039 self.index += 1;
1040 const result = %return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment);
1041 self.allocated_bytes += new_size - old_mem.len;
1042 return result;
1043 }
1044
1045 fn free(allocator: &mem.Allocator, bytes: []u8) {
1046 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
1047 self.allocated_bytes -= bytes.len;
1048 return self.internal_allocator.freeFn(self.internal_allocator, bytes);
1049 }
1050};
std/debug/failing_allocator.zig created+64
......@@ -0,0 +1,64 @@
1const std = @import("../index.zig");
2const mem = std.mem;
3
4/// Allocator that fails after N allocations, useful for making sure out of
5/// memory conditions are handled correctly.
6pub const FailingAllocator = struct {
7 allocator: mem.Allocator,
8 index: usize,
9 fail_index: usize,
10 internal_allocator: &mem.Allocator,
11 allocated_bytes: usize,
12 freed_bytes: usize,
13 deallocations: usize,
14
15 pub fn init(allocator: &mem.Allocator, fail_index: usize) -> FailingAllocator {
16 return FailingAllocator {
17 .internal_allocator = allocator,
18 .fail_index = fail_index,
19 .index = 0,
20 .allocated_bytes = 0,
21 .freed_bytes = 0,
22 .deallocations = 0,
23 .allocator = mem.Allocator {
24 .allocFn = alloc,
25 .reallocFn = realloc,
26 .freeFn = free,
27 },
28 };
29 }
30
31 fn alloc(allocator: &mem.Allocator, n: usize, alignment: u29) -> %[]u8 {
32 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
33 if (self.index == self.fail_index) {
34 return error.OutOfMemory;
35 }
36 const result = %return self.internal_allocator.allocFn(self.internal_allocator, n, alignment);
37 self.allocated_bytes += result.len;
38 self.index += 1;
39 return result;
40 }
41
42 fn realloc(allocator: &mem.Allocator, old_mem: []u8, new_size: usize, alignment: u29) -> %[]u8 {
43 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
44 if (new_size <= old_mem.len) {
45 self.freed_bytes += old_mem.len - new_size;
46 return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment);
47 }
48 if (self.index == self.fail_index) {
49 return error.OutOfMemory;
50 }
51 const result = %return self.internal_allocator.reallocFn(self.internal_allocator, old_mem, new_size, alignment);
52 self.allocated_bytes += new_size - old_mem.len;
53 self.deallocations += 1;
54 self.index += 1;
55 return result;
56 }
57
58 fn free(allocator: &mem.Allocator, bytes: []u8) {
59 const self = @fieldParentPtr(FailingAllocator, "allocator", allocator);
60 self.freed_bytes += bytes.len;
61 self.deallocations += 1;
62 return self.internal_allocator.freeFn(self.internal_allocator, bytes);
63 }
64};
std/debug/index.zig created+996
......@@ -0,0 +1,996 @@
1const std = @import("../index.zig");
2const math = std.math;
3const mem = std.mem;
4const io = std.io;
5const os = std.os;
6const elf = std.elf;
7const DW = std.dwarf;
8const ArrayList = std.ArrayList;
9const builtin = @import("builtin");
10
11pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator;
12
13error MissingDebugInfo;
14error InvalidDebugInfo;
15error UnsupportedDebugInfo;
16
17
18/// Tries to write to stderr, unbuffered, and ignores any error returned.
19/// Does not append a newline.
20/// TODO atomic/multithread support
21var stderr_file: io.File = undefined;
22var stderr_file_out_stream: io.FileOutStream = undefined;
23var stderr_stream: ?&io.OutStream = null;
24pub fn warn(comptime fmt: []const u8, args: ...) {
25 const stderr = getStderrStream() %% return;
26 stderr.print(fmt, args) %% return;
27}
28fn getStderrStream() -> %&io.OutStream {
29 if (stderr_stream) |st| {
30 return st;
31 } else {
32 stderr_file = %return io.getStdErr();
33 stderr_file_out_stream = io.FileOutStream.init(&stderr_file);
34 const st = &stderr_file_out_stream.stream;
35 stderr_stream = st;
36 return st;
37 }
38}
39
40/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
41pub fn dumpStackTrace() {
42 const stderr = getStderrStream() %% return;
43 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) %% return;
44}
45
46/// This function invokes undefined behavior when `ok` is `false`.
47/// In Debug and ReleaseSafe modes, calls to this function are always
48/// generated, and the `unreachable` statement triggers a panic.
49/// In ReleaseFast and ReleaseSmall modes, calls to this function can be
50/// optimized away.
51pub fn assert(ok: bool) {
52 if (!ok) {
53 // In ReleaseFast test mode, we still want assert(false) to crash, so
54 // we insert an explicit call to @panic instead of unreachable.
55 // TODO we should use `assertOrPanic` in tests and remove this logic.
56 if (builtin.is_test) {
57 @panic("assertion failure");
58 } else {
59 unreachable; // assertion failure
60 }
61 }
62}
63
64/// Call this function when you want to panic if the condition is not true.
65/// If `ok` is `false`, this function will panic in every release mode.
66pub fn assertOrPanic(ok: bool) {
67 if (!ok) {
68 @panic("assertion failure");
69 }
70}
71
72var panicking = false;
73/// This is the default panic implementation.
74pub fn panic(comptime format: []const u8, args: ...) -> noreturn {
75 // TODO an intrinsic that labels this as unlikely to be reached
76
77 // TODO
78 // if (@atomicRmw(AtomicOp.XChg, &panicking, true, AtomicOrder.SeqCst)) { }
79 if (panicking) {
80 // Panicked during a panic.
81 // TODO detect if a different thread caused the panic, because in that case
82 // we would want to return here instead of calling abort, so that the thread
83 // which first called panic can finish printing a stack trace.
84 os.abort();
85 } else {
86 panicking = true;
87 }
88
89 const stderr = getStderrStream() %% os.abort();
90 stderr.print(format ++ "\n", args) %% os.abort();
91 writeStackTrace(stderr, global_allocator, stderr_file.isTty(), 1) %% os.abort();
92
93 os.abort();
94}
95
96const GREEN = "\x1b[32;1m";
97const WHITE = "\x1b[37;1m";
98const DIM = "\x1b[2m";
99const RESET = "\x1b[0m";
100
101error PathNotFound;
102error InvalidDebugInfo;
103
104pub fn writeStackTrace(out_stream: &io.OutStream, allocator: &mem.Allocator, tty_color: bool,
105 ignore_frame_count: usize) -> %void
106{
107 switch (builtin.object_format) {
108 builtin.ObjectFormat.elf => {
109 var stack_trace = ElfStackTrace {
110 .self_exe_file = undefined,
111 .elf = undefined,
112 .debug_info = undefined,
113 .debug_abbrev = undefined,
114 .debug_str = undefined,
115 .debug_line = undefined,
116 .debug_ranges = null,
117 .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
118 .compile_unit_list = ArrayList(CompileUnit).init(allocator),
119 };
120 const st = &stack_trace;
121 st.self_exe_file = %return os.openSelfExe();
122 defer st.self_exe_file.close();
123
124 %return st.elf.openFile(allocator, &st.self_exe_file);
125 defer st.elf.close();
126
127 st.debug_info = (%return st.elf.findSection(".debug_info")) ?? return error.MissingDebugInfo;
128 st.debug_abbrev = (%return st.elf.findSection(".debug_abbrev")) ?? return error.MissingDebugInfo;
129 st.debug_str = (%return st.elf.findSection(".debug_str")) ?? return error.MissingDebugInfo;
130 st.debug_line = (%return st.elf.findSection(".debug_line")) ?? return error.MissingDebugInfo;
131 st.debug_ranges = (%return st.elf.findSection(".debug_ranges"));
132 %return scanAllCompileUnits(st);
133
134 var ignored_count: usize = 0;
135
136 var fp = @ptrToInt(@frameAddress());
137 while (fp != 0) : (fp = *@intToPtr(&const usize, fp)) {
138 if (ignored_count < ignore_frame_count) {
139 ignored_count += 1;
140 continue;
141 }
142
143 const return_address = *@intToPtr(&const usize, fp + @sizeOf(usize));
144
145 // TODO we really should be able to convert @sizeOf(usize) * 2 to a string literal
146 // at compile time. I'll call it issue #313
147 const ptr_hex = if (@sizeOf(usize) == 4) "0x{x8}" else "0x{x16}";
148
149 const compile_unit = findCompileUnit(st, return_address) %% {
150 %return out_stream.print("???:?:?: " ++ DIM ++ ptr_hex ++ " in ??? (???)" ++ RESET ++ "\n ???\n\n",
151 return_address);
152 continue;
153 };
154 const compile_unit_name = %return compile_unit.die.getAttrString(st, DW.AT_name);
155 if (getLineNumberInfo(st, compile_unit, usize(return_address) - 1)) |line_info| {
156 defer line_info.deinit();
157 %return out_stream.print(WHITE ++ "{}:{}:{}" ++ RESET ++ ": " ++
158 DIM ++ ptr_hex ++ " in ??? ({})" ++ RESET ++ "\n",
159 line_info.file_name, line_info.line, line_info.column,
160 return_address, compile_unit_name);
161 if (printLineFromFile(st.allocator(), out_stream, line_info)) {
162 if (line_info.column == 0) {
163 %return out_stream.write("\n");
164 } else {
165 {var col_i: usize = 1; while (col_i < line_info.column) : (col_i += 1) {
166 %return out_stream.writeByte(' ');
167 }}
168 %return out_stream.write(GREEN ++ "^" ++ RESET ++ "\n");
169 }
170 } else |err| switch (err) {
171 error.EndOfFile, error.PathNotFound => {},
172 else => return err,
173 }
174 } else |err| switch (err) {
175 error.MissingDebugInfo, error.InvalidDebugInfo => {
176 %return out_stream.print(ptr_hex ++ " in ??? ({})\n",
177 return_address, compile_unit_name);
178 },
179 else => return err,
180 }
181 }
182 },
183 builtin.ObjectFormat.coff => {
184 %return out_stream.write("(stack trace unavailable for COFF object format)\n");
185 },
186 builtin.ObjectFormat.macho => {
187 %return out_stream.write("(stack trace unavailable for Mach-O object format)\n");
188 },
189 builtin.ObjectFormat.wasm => {
190 %return out_stream.write("(stack trace unavailable for WASM object format)\n");
191 },
192 builtin.ObjectFormat.unknown => {
193 %return out_stream.write("(stack trace unavailable for unknown object format)\n");
194 },
195 }
196}
197
198fn printLineFromFile(allocator: &mem.Allocator, out_stream: &io.OutStream, line_info: &const LineInfo) -> %void {
199 var f = %return io.File.openRead(line_info.file_name, allocator);
200 defer f.close();
201 // TODO fstat and make sure that the file has the correct size
202
203 var buf: [os.page_size]u8 = undefined;
204 var line: usize = 1;
205 var column: usize = 1;
206 var abs_index: usize = 0;
207 while (true) {
208 const amt_read = %return f.read(buf[0..]);
209 const slice = buf[0..amt_read];
210
211 for (slice) |byte| {
212 if (line == line_info.line) {
213 %return out_stream.writeByte(byte);
214 if (byte == '\n') {
215 return;
216 }
217 }
218 if (byte == '\n') {
219 line += 1;
220 column = 1;
221 } else {
222 column += 1;
223 }
224 }
225
226 if (amt_read < buf.len)
227 return error.EndOfFile;
228 }
229}
230
231const ElfStackTrace = struct {
232 self_exe_file: io.File,
233 elf: elf.Elf,
234 debug_info: &elf.SectionHeader,
235 debug_abbrev: &elf.SectionHeader,
236 debug_str: &elf.SectionHeader,
237 debug_line: &elf.SectionHeader,
238 debug_ranges: ?&elf.SectionHeader,
239 abbrev_table_list: ArrayList(AbbrevTableHeader),
240 compile_unit_list: ArrayList(CompileUnit),
241
242 pub fn allocator(self: &const ElfStackTrace) -> &mem.Allocator {
243 return self.abbrev_table_list.allocator;
244 }
245
246 pub fn readString(self: &ElfStackTrace) -> %[]u8 {
247 var in_file_stream = io.FileInStream.init(&self.self_exe_file);
248 const in_stream = &in_file_stream.stream;
249 return readStringRaw(self.allocator(), in_stream);
250 }
251};
252
253const PcRange = struct {
254 start: u64,
255 end: u64,
256};
257
258const CompileUnit = struct {
259 version: u16,
260 is_64: bool,
261 die: &Die,
262 index: usize,
263 pc_range: ?PcRange,
264};
265
266const AbbrevTable = ArrayList(AbbrevTableEntry);
267
268const AbbrevTableHeader = struct {
269 // offset from .debug_abbrev
270 offset: u64,
271 table: AbbrevTable,
272};
273
274const AbbrevTableEntry = struct {
275 has_children: bool,
276 abbrev_code: u64,
277 tag_id: u64,
278 attrs: ArrayList(AbbrevAttr),
279};
280
281const AbbrevAttr = struct {
282 attr_id: u64,
283 form_id: u64,
284};
285
286const FormValue = union(enum) {
287 Address: u64,
288 Block: []u8,
289 Const: Constant,
290 ExprLoc: []u8,
291 Flag: bool,
292 SecOffset: u64,
293 Ref: []u8,
294 RefAddr: u64,
295 RefSig8: u64,
296 String: []u8,
297 StrPtr: u64,
298};
299
300const Constant = struct {
301 payload: []u8,
302 signed: bool,
303
304 fn asUnsignedLe(self: &const Constant) -> %u64 {
305 if (self.payload.len > @sizeOf(u64))
306 return error.InvalidDebugInfo;
307 if (self.signed)
308 return error.InvalidDebugInfo;
309 return mem.readInt(self.payload, u64, builtin.Endian.Little);
310 }
311};
312
313const Die = struct {
314 tag_id: u64,
315 has_children: bool,
316 attrs: ArrayList(Attr),
317
318 const Attr = struct {
319 id: u64,
320 value: FormValue,
321 };
322
323 fn getAttr(self: &const Die, id: u64) -> ?&const FormValue {
324 for (self.attrs.toSliceConst()) |*attr| {
325 if (attr.id == id)
326 return &attr.value;
327 }
328 return null;
329 }
330
331 fn getAttrAddr(self: &const Die, id: u64) -> %u64 {
332 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
333 return switch (*form_value) {
334 FormValue.Address => |value| value,
335 else => error.InvalidDebugInfo,
336 };
337 }
338
339 fn getAttrSecOffset(self: &const Die, id: u64) -> %u64 {
340 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
341 return switch (*form_value) {
342 FormValue.Const => |value| value.asUnsignedLe(),
343 FormValue.SecOffset => |value| value,
344 else => error.InvalidDebugInfo,
345 };
346 }
347
348 fn getAttrUnsignedLe(self: &const Die, id: u64) -> %u64 {
349 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
350 return switch (*form_value) {
351 FormValue.Const => |value| value.asUnsignedLe(),
352 else => error.InvalidDebugInfo,
353 };
354 }
355
356 fn getAttrString(self: &const Die, st: &ElfStackTrace, id: u64) -> %[]u8 {
357 const form_value = self.getAttr(id) ?? return error.MissingDebugInfo;
358 return switch (*form_value) {
359 FormValue.String => |value| value,
360 FormValue.StrPtr => |offset| getString(st, offset),
361 else => error.InvalidDebugInfo,
362 };
363 }
364};
365
366const FileEntry = struct {
367 file_name: []const u8,
368 dir_index: usize,
369 mtime: usize,
370 len_bytes: usize,
371};
372
373const LineInfo = struct {
374 line: usize,
375 column: usize,
376 file_name: []u8,
377 allocator: &mem.Allocator,
378
379 fn deinit(self: &const LineInfo) {
380 self.allocator.free(self.file_name);
381 }
382};
383
384const LineNumberProgram = struct {
385 address: usize,
386 file: usize,
387 line: isize,
388 column: usize,
389 is_stmt: bool,
390 basic_block: bool,
391 end_sequence: bool,
392
393 target_address: usize,
394 include_dirs: []const []const u8,
395 file_entries: &ArrayList(FileEntry),
396
397 prev_address: usize,
398 prev_file: usize,
399 prev_line: isize,
400 prev_column: usize,
401 prev_is_stmt: bool,
402 prev_basic_block: bool,
403 prev_end_sequence: bool,
404
405 pub fn init(is_stmt: bool, include_dirs: []const []const u8,
406 file_entries: &ArrayList(FileEntry), target_address: usize) -> LineNumberProgram
407 {
408 return LineNumberProgram {
409 .address = 0,
410 .file = 1,
411 .line = 1,
412 .column = 0,
413 .is_stmt = is_stmt,
414 .basic_block = false,
415 .end_sequence = false,
416 .include_dirs = include_dirs,
417 .file_entries = file_entries,
418 .target_address = target_address,
419 .prev_address = 0,
420 .prev_file = undefined,
421 .prev_line = undefined,
422 .prev_column = undefined,
423 .prev_is_stmt = undefined,
424 .prev_basic_block = undefined,
425 .prev_end_sequence = undefined,
426 };
427 }
428
429 pub fn checkLineMatch(self: &LineNumberProgram) -> %?LineInfo {
430 if (self.target_address >= self.prev_address and self.target_address < self.address) {
431 const file_entry = if (self.prev_file == 0) {
432 return error.MissingDebugInfo;
433 } else if (self.prev_file - 1 >= self.file_entries.len) {
434 return error.InvalidDebugInfo;
435 } else &self.file_entries.items[self.prev_file - 1];
436
437 const dir_name = if (file_entry.dir_index >= self.include_dirs.len) {
438 return error.InvalidDebugInfo;
439 } else self.include_dirs[file_entry.dir_index];
440 const file_name = %return os.path.join(self.file_entries.allocator, dir_name, file_entry.file_name);
441 %defer self.file_entries.allocator.free(file_name);
442 return LineInfo {
443 .line = if (self.prev_line >= 0) usize(self.prev_line) else 0,
444 .column = self.prev_column,
445 .file_name = file_name,
446 .allocator = self.file_entries.allocator,
447 };
448 }
449
450 self.prev_address = self.address;
451 self.prev_file = self.file;
452 self.prev_line = self.line;
453 self.prev_column = self.column;
454 self.prev_is_stmt = self.is_stmt;
455 self.prev_basic_block = self.basic_block;
456 self.prev_end_sequence = self.end_sequence;
457 return null;
458 }
459};
460
461fn readStringRaw(allocator: &mem.Allocator, in_stream: &io.InStream) -> %[]u8 {
462 var buf = ArrayList(u8).init(allocator);
463 while (true) {
464 const byte = %return in_stream.readByte();
465 if (byte == 0)
466 break;
467 %return buf.append(byte);
468 }
469 return buf.toSlice();
470}
471
472fn getString(st: &ElfStackTrace, offset: u64) -> %[]u8 {
473 const pos = st.debug_str.offset + offset;
474 %return st.self_exe_file.seekTo(pos);
475 return st.readString();
476}
477
478fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %[]u8 {
479 const buf = %return global_allocator.alloc(u8, size);
480 %defer global_allocator.free(buf);
481 if ((%return in_stream.read(buf)) < size) return error.EndOfFile;
482 return buf;
483}
484
485fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
486 const buf = %return readAllocBytes(allocator, in_stream, size);
487 return FormValue { .Block = buf };
488}
489
490fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
491 const block_len = %return in_stream.readVarInt(builtin.Endian.Little, usize, size);
492 return parseFormValueBlockLen(allocator, in_stream, block_len);
493}
494
495fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
496 return FormValue { .Const = Constant {
497 .signed = signed,
498 .payload = %return readAllocBytes(allocator, in_stream, size),
499 }};
500}
501
502fn parseFormValueDwarfOffsetSize(in_stream: &io.InStream, is_64: bool) -> %u64 {
503 return if (is_64) %return in_stream.readIntLe(u64)
504 else u64(%return in_stream.readIntLe(u32)) ;
505}
506
507fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
508 return if (@sizeOf(usize) == 4) u64(%return in_stream.readIntLe(u32))
509 else if (@sizeOf(usize) == 8) %return in_stream.readIntLe(u64)
510 else unreachable;
511}
512
513fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
514 const buf = %return readAllocBytes(allocator, in_stream, size);
515 return FormValue { .Ref = buf };
516}
517
518fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) -> %FormValue {
519 const block_len = %return in_stream.readIntLe(T);
520 return parseFormValueRefLen(allocator, in_stream, block_len);
521}
522
523fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) -> %FormValue {
524 return switch (form_id) {
525 DW.FORM_addr => FormValue { .Address = %return parseFormValueTargetAddrSize(in_stream) },
526 DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
527 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
528 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
529 DW.FORM_block => x: {
530 const block_len = %return readULeb128(in_stream);
531 return parseFormValueBlockLen(allocator, in_stream, block_len);
532 },
533 DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
534 DW.FORM_data2 => parseFormValueConstant(allocator, in_stream, false, 2),
535 DW.FORM_data4 => parseFormValueConstant(allocator, in_stream, false, 4),
536 DW.FORM_data8 => parseFormValueConstant(allocator, in_stream, false, 8),
537 DW.FORM_udata, DW.FORM_sdata => {
538 const block_len = %return readULeb128(in_stream);
539 const signed = form_id == DW.FORM_sdata;
540 return parseFormValueConstant(allocator, in_stream, signed, block_len);
541 },
542 DW.FORM_exprloc => {
543 const size = %return readULeb128(in_stream);
544 const buf = %return readAllocBytes(allocator, in_stream, size);
545 return FormValue { .ExprLoc = buf };
546 },
547 DW.FORM_flag => FormValue { .Flag = (%return in_stream.readByte()) != 0 },
548 DW.FORM_flag_present => FormValue { .Flag = true },
549 DW.FORM_sec_offset => FormValue { .SecOffset = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
550
551 DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
552 DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
553 DW.FORM_ref4 => parseFormValueRef(allocator, in_stream, u32),
554 DW.FORM_ref8 => parseFormValueRef(allocator, in_stream, u64),
555 DW.FORM_ref_udata => {
556 const ref_len = %return readULeb128(in_stream);
557 return parseFormValueRefLen(allocator, in_stream, ref_len);
558 },
559
560 DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
561 DW.FORM_ref_sig8 => FormValue { .RefSig8 = %return in_stream.readIntLe(u64) },
562
563 DW.FORM_string => FormValue { .String = %return readStringRaw(allocator, in_stream) },
564 DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
565 DW.FORM_indirect => {
566 const child_form_id = %return readULeb128(in_stream);
567 return parseFormValue(allocator, in_stream, child_form_id, is_64);
568 },
569 else => error.InvalidDebugInfo,
570 };
571}
572
573fn parseAbbrevTable(st: &ElfStackTrace) -> %AbbrevTable {
574 const in_file = &st.self_exe_file;
575 var in_file_stream = io.FileInStream.init(in_file);
576 const in_stream = &in_file_stream.stream;
577 var result = AbbrevTable.init(st.allocator());
578 while (true) {
579 const abbrev_code = %return readULeb128(in_stream);
580 if (abbrev_code == 0)
581 return result;
582 %return result.append(AbbrevTableEntry {
583 .abbrev_code = abbrev_code,
584 .tag_id = %return readULeb128(in_stream),
585 .has_children = (%return in_stream.readByte()) == DW.CHILDREN_yes,
586 .attrs = ArrayList(AbbrevAttr).init(st.allocator()),
587 });
588 const attrs = &result.items[result.len - 1].attrs;
589
590 while (true) {
591 const attr_id = %return readULeb128(in_stream);
592 const form_id = %return readULeb128(in_stream);
593 if (attr_id == 0 and form_id == 0)
594 break;
595 %return attrs.append(AbbrevAttr {
596 .attr_id = attr_id,
597 .form_id = form_id,
598 });
599 }
600 }
601}
602
603/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
604/// seeks in the stream and parses it.
605fn getAbbrevTable(st: &ElfStackTrace, abbrev_offset: u64) -> %&const AbbrevTable {
606 for (st.abbrev_table_list.toSlice()) |*header| {
607 if (header.offset == abbrev_offset) {
608 return &header.table;
609 }
610 }
611 %return st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
612 %return st.abbrev_table_list.append(AbbrevTableHeader {
613 .offset = abbrev_offset,
614 .table = %return parseAbbrevTable(st),
615 });
616 return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table;
617}
618
619fn getAbbrevTableEntry(abbrev_table: &const AbbrevTable, abbrev_code: u64) -> ?&const AbbrevTableEntry {
620 for (abbrev_table.toSliceConst()) |*table_entry| {
621 if (table_entry.abbrev_code == abbrev_code)
622 return table_entry;
623 }
624 return null;
625}
626
627fn parseDie(st: &ElfStackTrace, abbrev_table: &const AbbrevTable, is_64: bool) -> %Die {
628 const in_file = &st.self_exe_file;
629 var in_file_stream = io.FileInStream.init(in_file);
630 const in_stream = &in_file_stream.stream;
631 const abbrev_code = %return readULeb128(in_stream);
632 const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) ?? return error.InvalidDebugInfo;
633
634 var result = Die {
635 .tag_id = table_entry.tag_id,
636 .has_children = table_entry.has_children,
637 .attrs = ArrayList(Die.Attr).init(st.allocator()),
638 };
639 %return result.attrs.resize(table_entry.attrs.len);
640 for (table_entry.attrs.toSliceConst()) |attr, i| {
641 result.attrs.items[i] = Die.Attr {
642 .id = attr.attr_id,
643 .value = %return parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
644 };
645 }
646 return result;
647}
648
649fn getLineNumberInfo(st: &ElfStackTrace, compile_unit: &const CompileUnit, target_address: usize) -> %LineInfo {
650 const compile_unit_cwd = %return compile_unit.die.getAttrString(st, DW.AT_comp_dir);
651
652 const in_file = &st.self_exe_file;
653 const debug_line_end = st.debug_line.offset + st.debug_line.size;
654 var this_offset = st.debug_line.offset;
655 var this_index: usize = 0;
656
657 var in_file_stream = io.FileInStream.init(in_file);
658 const in_stream = &in_file_stream.stream;
659
660 while (this_offset < debug_line_end) : (this_index += 1) {
661 %return in_file.seekTo(this_offset);
662
663 var is_64: bool = undefined;
664 const unit_length = %return readInitialLength(in_stream, &is_64);
665 if (unit_length == 0)
666 return error.MissingDebugInfo;
667 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
668
669 if (compile_unit.index != this_index) {
670 this_offset += next_offset;
671 continue;
672 }
673
674 const version = %return in_stream.readInt(st.elf.endian, u16);
675 if (version != 2) return error.InvalidDebugInfo;
676
677 const prologue_length = %return in_stream.readInt(st.elf.endian, u32);
678 const prog_start_offset = (%return in_file.getPos()) + prologue_length;
679
680 const minimum_instruction_length = %return in_stream.readByte();
681 if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
682
683 const default_is_stmt = (%return in_stream.readByte()) != 0;
684 const line_base = %return in_stream.readByteSigned();
685
686 const line_range = %return in_stream.readByte();
687 if (line_range == 0)
688 return error.InvalidDebugInfo;
689
690 const opcode_base = %return in_stream.readByte();
691
692 const standard_opcode_lengths = %return st.allocator().alloc(u8, opcode_base - 1);
693
694 {var i: usize = 0; while (i < opcode_base - 1) : (i += 1) {
695 standard_opcode_lengths[i] = %return in_stream.readByte();
696 }}
697
698 var include_directories = ArrayList([]u8).init(st.allocator());
699 %return include_directories.append(compile_unit_cwd);
700 while (true) {
701 const dir = %return st.readString();
702 if (dir.len == 0)
703 break;
704 %return include_directories.append(dir);
705 }
706
707 var file_entries = ArrayList(FileEntry).init(st.allocator());
708 var prog = LineNumberProgram.init(default_is_stmt, include_directories.toSliceConst(),
709 &file_entries, target_address);
710
711 while (true) {
712 const file_name = %return st.readString();
713 if (file_name.len == 0)
714 break;
715 const dir_index = %return readULeb128(in_stream);
716 const mtime = %return readULeb128(in_stream);
717 const len_bytes = %return readULeb128(in_stream);
718 %return file_entries.append(FileEntry {
719 .file_name = file_name,
720 .dir_index = dir_index,
721 .mtime = mtime,
722 .len_bytes = len_bytes,
723 });
724 }
725
726 %return in_file.seekTo(prog_start_offset);
727
728 while (true) {
729 const opcode = %return in_stream.readByte();
730
731 var sub_op: u8 = undefined; // TODO move this to the correct scope and fix the compiler crash
732 if (opcode == DW.LNS_extended_op) {
733 const op_size = %return readULeb128(in_stream);
734 if (op_size < 1)
735 return error.InvalidDebugInfo;
736 sub_op = %return in_stream.readByte();
737 switch (sub_op) {
738 DW.LNE_end_sequence => {
739 prog.end_sequence = true;
740 if (%return prog.checkLineMatch()) |info| return info;
741 return error.MissingDebugInfo;
742 },
743 DW.LNE_set_address => {
744 const addr = %return in_stream.readInt(st.elf.endian, usize);
745 prog.address = addr;
746 },
747 DW.LNE_define_file => {
748 const file_name = %return st.readString();
749 const dir_index = %return readULeb128(in_stream);
750 const mtime = %return readULeb128(in_stream);
751 const len_bytes = %return readULeb128(in_stream);
752 %return file_entries.append(FileEntry {
753 .file_name = file_name,
754 .dir_index = dir_index,
755 .mtime = mtime,
756 .len_bytes = len_bytes,
757 });
758 },
759 else => {
760 const fwd_amt = math.cast(isize, op_size - 1) %% return error.InvalidDebugInfo;
761 %return in_file.seekForward(fwd_amt);
762 },
763 }
764 } else if (opcode >= opcode_base) {
765 // special opcodes
766 const adjusted_opcode = opcode - opcode_base;
767 const inc_addr = minimum_instruction_length * (adjusted_opcode / line_range);
768 const inc_line = i32(line_base) + i32(adjusted_opcode % line_range);
769 prog.line += inc_line;
770 prog.address += inc_addr;
771 if (%return prog.checkLineMatch()) |info| return info;
772 prog.basic_block = false;
773 } else {
774 switch (opcode) {
775 DW.LNS_copy => {
776 if (%return prog.checkLineMatch()) |info| return info;
777 prog.basic_block = false;
778 },
779 DW.LNS_advance_pc => {
780 const arg = %return readULeb128(in_stream);
781 prog.address += arg * minimum_instruction_length;
782 },
783 DW.LNS_advance_line => {
784 const arg = %return readILeb128(in_stream);
785 prog.line += arg;
786 },
787 DW.LNS_set_file => {
788 const arg = %return readULeb128(in_stream);
789 prog.file = arg;
790 },
791 DW.LNS_set_column => {
792 const arg = %return readULeb128(in_stream);
793 prog.column = arg;
794 },
795 DW.LNS_negate_stmt => {
796 prog.is_stmt = !prog.is_stmt;
797 },
798 DW.LNS_set_basic_block => {
799 prog.basic_block = true;
800 },
801 DW.LNS_const_add_pc => {
802 const inc_addr = minimum_instruction_length * ((255 - opcode_base) / line_range);
803 prog.address += inc_addr;
804 },
805 DW.LNS_fixed_advance_pc => {
806 const arg = %return in_stream.readInt(st.elf.endian, u16);
807 prog.address += arg;
808 },
809 DW.LNS_set_prologue_end => {
810 },
811 else => {
812 if (opcode - 1 >= standard_opcode_lengths.len)
813 return error.InvalidDebugInfo;
814 const len_bytes = standard_opcode_lengths[opcode - 1];
815 %return in_file.seekForward(len_bytes);
816 },
817 }
818 }
819 }
820
821 this_offset += next_offset;
822 }
823
824 return error.MissingDebugInfo;
825}
826
827fn scanAllCompileUnits(st: &ElfStackTrace) -> %void {
828 const debug_info_end = st.debug_info.offset + st.debug_info.size;
829 var this_unit_offset = st.debug_info.offset;
830 var cu_index: usize = 0;
831
832 var in_file_stream = io.FileInStream.init(&st.self_exe_file);
833 const in_stream = &in_file_stream.stream;
834
835 while (this_unit_offset < debug_info_end) {
836 %return st.self_exe_file.seekTo(this_unit_offset);
837
838 var is_64: bool = undefined;
839 const unit_length = %return readInitialLength(in_stream, &is_64);
840 if (unit_length == 0)
841 return;
842 const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
843
844 const version = %return in_stream.readInt(st.elf.endian, u16);
845 if (version < 2 or version > 5) return error.InvalidDebugInfo;
846
847 const debug_abbrev_offset =
848 if (is_64) %return in_stream.readInt(st.elf.endian, u64)
849 else %return in_stream.readInt(st.elf.endian, u32);
850
851 const address_size = %return in_stream.readByte();
852 if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
853
854 const compile_unit_pos = %return st.self_exe_file.getPos();
855 const abbrev_table = %return getAbbrevTable(st, debug_abbrev_offset);
856
857 %return st.self_exe_file.seekTo(compile_unit_pos);
858
859 const compile_unit_die = %return st.allocator().create(Die);
860 *compile_unit_die = %return parseDie(st, abbrev_table, is_64);
861
862 if (compile_unit_die.tag_id != DW.TAG_compile_unit)
863 return error.InvalidDebugInfo;
864
865 const pc_range = x: {
866 if (compile_unit_die.getAttrAddr(DW.AT_low_pc)) |low_pc| {
867 if (compile_unit_die.getAttr(DW.AT_high_pc)) |high_pc_value| {
868 const pc_end = switch (*high_pc_value) {
869 FormValue.Address => |value| value,
870 FormValue.Const => |value| b: {
871 const offset = %return value.asUnsignedLe();
872 break :b (low_pc + offset);
873 },
874 else => return error.InvalidDebugInfo,
875 };
876 break :x PcRange {
877 .start = low_pc,
878 .end = pc_end,
879 };
880 } else {
881 break :x null;
882 }
883 } else |err| {
884 if (err != error.MissingDebugInfo)
885 return err;
886 break :x null;
887 }
888 };
889
890 %return st.compile_unit_list.append(CompileUnit {
891 .version = version,
892 .is_64 = is_64,
893 .pc_range = pc_range,
894 .die = compile_unit_die,
895 .index = cu_index,
896 });
897
898 this_unit_offset += next_offset;
899 cu_index += 1;
900 }
901}
902
903fn findCompileUnit(st: &ElfStackTrace, target_address: u64) -> %&const CompileUnit {
904 var in_file_stream = io.FileInStream.init(&st.self_exe_file);
905 const in_stream = &in_file_stream.stream;
906 for (st.compile_unit_list.toSlice()) |*compile_unit| {
907 if (compile_unit.pc_range) |range| {
908 if (target_address >= range.start and target_address < range.end)
909 return compile_unit;
910 }
911 if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
912 var base_address: usize = 0;
913 if (st.debug_ranges) |debug_ranges| {
914 %return st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset);
915 while (true) {
916 const begin_addr = %return in_stream.readIntLe(usize);
917 const end_addr = %return in_stream.readIntLe(usize);
918 if (begin_addr == 0 and end_addr == 0) {
919 break;
920 }
921 if (begin_addr == @maxValue(usize)) {
922 base_address = begin_addr;
923 continue;
924 }
925 if (target_address >= begin_addr and target_address < end_addr) {
926 return compile_unit;
927 }
928 }
929 }
930 } else |err| {
931 if (err != error.MissingDebugInfo)
932 return err;
933 continue;
934 }
935 }
936 return error.MissingDebugInfo;
937}
938
939fn readInitialLength(in_stream: &io.InStream, is_64: &bool) -> %u64 {
940 const first_32_bits = %return in_stream.readIntLe(u32);
941 *is_64 = (first_32_bits == 0xffffffff);
942 if (*is_64) {
943 return in_stream.readIntLe(u64);
944 } else {
945 if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
946 return u64(first_32_bits);
947 }
948}
949
950fn readULeb128(in_stream: &io.InStream) -> %u64 {
951 var result: u64 = 0;
952 var shift: usize = 0;
953
954 while (true) {
955 const byte = %return in_stream.readByte();
956
957 var operand: u64 = undefined;
958
959 if (@shlWithOverflow(u64, byte & 0b01111111, u6(shift), &operand))
960 return error.InvalidDebugInfo;
961
962 result |= operand;
963
964 if ((byte & 0b10000000) == 0)
965 return result;
966
967 shift += 7;
968 }
969}
970
971fn readILeb128(in_stream: &io.InStream) -> %i64 {
972 var result: i64 = 0;
973 var shift: usize = 0;
974
975 while (true) {
976 const byte = %return in_stream.readByte();
977
978 var operand: i64 = undefined;
979
980 if (@shlWithOverflow(i64, byte & 0b01111111, u6(shift), &operand))
981 return error.InvalidDebugInfo;
982
983 result |= operand;
984 shift += 7;
985
986 if ((byte & 0b10000000) == 0) {
987 if (shift < @sizeOf(i64) * 8 and (byte & 0b01000000) != 0)
988 result |= -(i64(1) << u6(shift));
989 return result;
990 }
991 }
992}
993
994pub const global_allocator = &global_fixed_allocator.allocator;
995var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]);
996var global_allocator_mem: [100 * 1024]u8 = undefined;
std/fmt/errol/index.zig+4-3
......@@ -1,10 +1,11 @@
1const std = @import("../../index.zig");
12const enum3 = @import("enum3.zig").enum3;
23const enum3_data = @import("enum3.zig").enum3_data;
34const lookup_table = @import("lookup.zig").lookup_table;
45const HP = @import("lookup.zig").HP;
5const math = @import("../../math/index.zig");
6const mem = @import("../../mem.zig");
7const assert = @import("../../debug.zig").assert;
6const math = std.math;
7const mem = std.mem;
8const assert = std.debug.assert;
89
910pub const FloatDecimal = struct {
1011 digits: []u8,
std/fmt/index.zig+4-3
......@@ -1,7 +1,8 @@
1const math = @import("../math/index.zig");
2const debug = @import("../debug.zig");
1const std = @import("../index.zig");
2const math = std.math;
3const debug = std.debug;
34const assert = debug.assert;
4const mem = @import("../mem.zig");
5const mem = std.mem;
56const builtin = @import("builtin");
67const errol3 = @import("errol/index.zig").errol3;
78
std/hash_map.zig+4-3
......@@ -1,7 +1,8 @@
1const debug = @import("debug.zig");
1const std = @import("index.zig");
2const debug = std.debug;
23const assert = debug.assert;
3const math = @import("math/index.zig");
4const mem = @import("mem.zig");
4const math = std.math;
5const mem = std.mem;
56const Allocator = mem.Allocator;
67const builtin = @import("builtin");
78
std/heap.zig+5-4
......@@ -1,10 +1,11 @@
1const debug = @import("debug.zig");
1const std = @import("index.zig");
2const debug = std.debug;
23const assert = debug.assert;
3const mem = @import("mem.zig");
4const os = @import("os/index.zig");
4const mem = std.mem;
5const os = std.os;
56const builtin = @import("builtin");
67const Os = builtin.Os;
7const c = @import("c/index.zig");
8const c = std.c;
89
910const Allocator = mem.Allocator;
1011
std/index.zig+2-2
......@@ -11,7 +11,7 @@ pub const base64 = @import("base64.zig");
1111pub const build = @import("build.zig");
1212pub const c = @import("c/index.zig");
1313pub const cstr = @import("cstr.zig");
14pub const debug = @import("debug.zig");
14pub const debug = @import("debug/index.zig");
1515pub const dwarf = @import("dwarf.zig");
1616pub const elf = @import("elf.zig");
1717pub const empty_import = @import("empty.zig");
......@@ -39,7 +39,7 @@ test "std" {
3939 _ = @import("build.zig");
4040 _ = @import("c/index.zig");
4141 _ = @import("cstr.zig");
42 _ = @import("debug.zig");
42 _ = @import("debug/index.zig");
4343 _ = @import("dwarf.zig");
4444 _ = @import("elf.zig");
4545 _ = @import("empty.zig");
std/linked_list.zig+3-2
......@@ -1,6 +1,7 @@
1const debug = @import("debug.zig");
1const std = @import("index.zig");
2const debug = std.debug;
23const assert = debug.assert;
3const mem = @import("mem.zig");
4const mem = std.mem;
45const Allocator = mem.Allocator;
56
67/// Generic doubly linked list.
std/math/acos.zig+3-2
......@@ -2,8 +2,9 @@
22//
33// - acos(x) = nan if x < -1 or x > 1
44
5const math = @import("index.zig");
6const assert = @import("../debug.zig").assert;
5const std = @import("../index.zig");
6const math = std.math;
7const assert = std.debug.assert;
78
89pub fn acos(x: var) -> @typeOf(x) {
910 const T = @typeOf(x);
std/math/acosh.zig+3-2
......@@ -4,8 +4,9 @@
44// - acosh(nan) = nan
55
66const builtin = @import("builtin");
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn acosh(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/math/asin.zig+3-2
......@@ -3,8 +3,9 @@
33// - asin(+-0) = +-0
44// - asin(x) = nan if x < -1 or x > 1
55
6const math = @import("index.zig");
7const assert = @import("../debug.zig").assert;
6const std = @import("../index.zig");
7const math = std.math;
8const assert = std.debug.assert;
89
910pub fn asin(x: var) -> @typeOf(x) {
1011 const T = @typeOf(x);
std/math/asinh.zig+3-2
......@@ -4,8 +4,9 @@
44// - asinh(+-inf) = +-inf
55// - asinh(nan) = nan
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn asinh(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/math/atan.zig+3-2
......@@ -3,8 +3,9 @@
33// - atan(+-0) = +-0
44// - atan(+-inf) = +-pi/2
55
6const math = @import("index.zig");
7const assert = @import("../debug.zig").assert;
6const std = @import("../index.zig");
7const math = std.math;
8const assert = std.debug.assert;
89
910pub fn atan(x: var) -> @typeOf(x) {
1011 const T = @typeOf(x);
std/math/atan2.zig+3-2
......@@ -18,8 +18,9 @@
1818// atan2(+inf, x) = +pi/2
1919// atan2(-inf, x) = -pi/2
2020
21const math = @import("index.zig");
22const assert = @import("../debug.zig").assert;
21const std = @import("../index.zig");
22const math = std.math;
23const assert = std.debug.assert;
2324
2425fn atan2(comptime T: type, x: T, y: T) -> T {
2526 return switch (T) {
std/math/atanh.zig+3-2
......@@ -4,8 +4,9 @@
44// - atanh(x) = nan if |x| > 1 with signal
55// - atanh(nan) = nan
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn atanh(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/math/cbrt.zig+3-2
......@@ -4,8 +4,9 @@
44// - cbrt(+-inf) = +-inf
55// - cbrt(nan) = nan
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn cbrt(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/math/ceil.zig+3-2
......@@ -5,8 +5,9 @@
55// - ceil(nan) = nan
66
77const builtin = @import("builtin");
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011
1112pub fn ceil(x: var) -> @typeOf(x) {
1213 const T = @typeOf(x);
std/math/copysign.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn copysign(comptime T: type, x: T, y: T) -> T {
56 return switch (T) {
std/math/cos.zig+3-2
......@@ -4,8 +4,9 @@
44// - cos(nan) = nan
55
66const builtin = @import("builtin");
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn cos(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/math/cosh.zig+3-2
......@@ -5,9 +5,10 @@
55// - cosh(nan) = nan
66
77const builtin = @import("builtin");
8const math = @import("index.zig");
8const std = @import("../index.zig");
9const math = std.math;
910const expo2 = @import("expo2.zig").expo2;
10const assert = @import("../debug.zig").assert;
11const assert = std.debug.assert;
1112
1213pub fn cosh(x: var) -> @typeOf(x) {
1314 const T = @typeOf(x);
std/math/exp.zig+3-2
......@@ -3,8 +3,9 @@
33// - exp(+inf) = +inf
44// - exp(nan) = nan
55
6const math = @import("index.zig");
7const assert = @import("../debug.zig").assert;
6const std = @import("../index.zig");
7const math = std.math;
8const assert = std.debug.assert;
89
910pub fn exp(x: var) -> @typeOf(x) {
1011 const T = @typeOf(x);
std/math/exp2.zig+3-2
......@@ -3,8 +3,9 @@
33// - exp2(+inf) = +inf
44// - exp2(nan) = nan
55
6const math = @import("index.zig");
7const assert = @import("../debug.zig").assert;
6const std = @import("../index.zig");
7const math = std.math;
8const assert = std.debug.assert;
89
910pub fn exp2(x: var) -> @typeOf(x) {
1011 const T = @typeOf(x);
std/math/expm1.zig+3-2
......@@ -4,8 +4,9 @@
44// - expm1(-inf) = -1
55// - expm1(nan) = nan
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn expm1(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/math/fabs.zig+3-2
......@@ -3,8 +3,9 @@
33// - fabs(+-inf) = +inf
44// - fabs(nan) = nan
55
6const math = @import("index.zig");
7const assert = @import("../debug.zig").assert;
6const std = @import("../index.zig");
7const math = std.math;
8const assert = std.debug.assert;
89
910pub fn fabs(x: var) -> @typeOf(x) {
1011 const T = @typeOf(x);
std/math/floor.zig+3-2
......@@ -5,8 +5,9 @@
55// - floor(nan) = nan
66
77const builtin = @import("builtin");
8const assert = @import("../debug.zig").assert;
9const math = @import("index.zig");
8const assert = std.debug.assert;
9const std = @import("../index.zig");
10const math = std.math;
1011
1112pub fn floor(x: var) -> @typeOf(x) {
1213 const T = @typeOf(x);
std/math/fma.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn fma(comptime T: type, x: T, y: T, z: T) -> T {
56 return switch (T) {
std/math/frexp.zig+3-2
......@@ -4,8 +4,9 @@
44// - frexp(+-inf) = +-inf, 0
55// - frexp(nan) = nan, undefined
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011fn frexp_result(comptime T: type) -> type {
1112 return struct {
std/math/hypot.zig+3-2
......@@ -5,8 +5,9 @@
55// - hypot(nan, y) = nan
66// - hypot(x, nan) = nan
77
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011
1112pub fn hypot(comptime T: type, x: T, y: T) -> T {
1213 return switch (T) {
std/math/ilogb.zig+3-2
......@@ -4,8 +4,9 @@
44// - ilogb(0) = @maxValue(i32)
55// - ilogb(nan) = @maxValue(i32)
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn ilogb(x: var) -> i32 {
1112 const T = @typeOf(x);
std/math/index.zig+2-1
......@@ -1,6 +1,7 @@
11const builtin = @import("builtin");
2const std = @import("../index.zig");
23const TypeId = builtin.TypeId;
3const assert = @import("../debug.zig").assert;
4const assert = std.debug.assert;
45
56pub const e = 2.71828182845904523536028747135266249775724709369995;
67pub const pi = 3.14159265358979323846264338327950288419716939937510;
std/math/inf.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn inf(comptime T: type) -> T {
56 return switch (T) {
std/math/isfinite.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn isFinite(x: var) -> bool {
56 const T = @typeOf(x);
std/math/isinf.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn isInf(x: var) -> bool {
56 const T = @typeOf(x);
std/math/isnan.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn isNan(x: var) -> bool {
56 const T = @typeOf(x);
std/math/isnormal.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn isNormal(x: var) -> bool {
56 const T = @typeOf(x);
std/math/ln.zig+3-2
......@@ -5,8 +5,9 @@
55// - ln(x) = nan if x < 0
66// - ln(nan) = nan
77
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011const builtin = @import("builtin");
1112const TypeId = builtin.TypeId;
1213
std/math/log.zig+3-2
......@@ -1,7 +1,8 @@
1const math = @import("index.zig");
1const std = @import("../index.zig");
2const math = std.math;
23const builtin = @import("builtin");
34const TypeId = builtin.TypeId;
4const assert = @import("../debug.zig").assert;
5const assert = std.debug.assert;
56
67pub fn log(comptime T: type, base: T, x: T) -> T {
78 if (base == 2) {
std/math/log10.zig+3-2
......@@ -5,8 +5,9 @@
55// - log10(x) = nan if x < 0
66// - log10(nan) = nan
77
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011const builtin = @import("builtin");
1112const TypeId = builtin.TypeId;
1213
std/math/log1p.zig+3-2
......@@ -6,8 +6,9 @@
66// - log1p(x) = nan if x < -1
77// - log1p(nan) = nan
88
9const math = @import("index.zig");
10const assert = @import("../debug.zig").assert;
9const std = @import("../index.zig");
10const math = std.math;
11const assert = std.debug.assert;
1112
1213pub fn log1p(x: var) -> @typeOf(x) {
1314 const T = @typeOf(x);
std/math/log2.zig+3-2
......@@ -5,8 +5,9 @@
55// - log2(x) = nan if x < 0
66// - log2(nan) = nan
77
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011const builtin = @import("builtin");
1112const TypeId = builtin.TypeId;
1213
std/math/modf.zig+3-2
......@@ -3,8 +3,9 @@
33// - modf(+-inf) = +-inf, nan
44// - modf(nan) = nan, nan
55
6const math = @import("index.zig");
7const assert = @import("../debug.zig").assert;
6const std = @import("../index.zig");
7const math = std.math;
8const assert = std.debug.assert;
89
910fn modf_result(comptime T: type) -> type {
1011 return struct {
std/math/pow.zig+3-2
......@@ -22,8 +22,9 @@
2222// pow(x, y) = nan for finite x < 0 and finite non-integer y
2323
2424const builtin = @import("builtin");
25const math = @import("index.zig");
26const assert = @import("../debug.zig").assert;
25const std = @import("../index.zig");
26const math = std.math;
27const assert = std.debug.assert;
2728
2829// This implementation is taken from the go stlib, musl is a bit more complex.
2930pub fn pow(comptime T: type, x: T, y: T) -> T {
std/math/round.zig+3-2
......@@ -5,8 +5,9 @@
55// - round(nan) = nan
66
77const builtin = @import("builtin");
8const assert = @import("../debug.zig").assert;
9const math = @import("index.zig");
8const assert = std.debug.assert;
9const std = @import("../index.zig");
10const math = std.math;
1011
1112pub fn round(x: var) -> @typeOf(x) {
1213 const T = @typeOf(x);
std/math/scalbn.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn scalbn(x: var, n: i32) -> @typeOf(x) {
56 const T = @typeOf(x);
std/math/signbit.zig+3-2
......@@ -1,5 +1,6 @@
1const math = @import("index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const math = std.math;
3const assert = std.debug.assert;
34
45pub fn signbit(x: var) -> bool {
56 const T = @typeOf(x);
std/math/sin.zig+3-2
......@@ -5,8 +5,9 @@
55// - sin(nan) = nan
66
77const builtin = @import("builtin");
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011
1112pub fn sin(x: var) -> @typeOf(x) {
1213 const T = @typeOf(x);
std/math/sinh.zig+3-2
......@@ -5,8 +5,9 @@
55// - sinh(nan) = nan
66
77const builtin = @import("builtin");
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011const expo2 = @import("expo2.zig").expo2;
1112
1213pub fn sinh(x: var) -> @typeOf(x) {
std/math/sqrt.zig+3-2
......@@ -5,8 +5,9 @@
55// - sqrt(x) = nan if x < 0
66// - sqrt(nan) = nan
77
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011const builtin = @import("builtin");
1112const TypeId = builtin.TypeId;
1213
std/math/tan.zig+3-2
......@@ -5,8 +5,9 @@
55// - tan(nan) = nan
66
77const builtin = @import("builtin");
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011
1112pub fn tan(x: var) -> @typeOf(x) {
1213 const T = @typeOf(x);
std/math/tanh.zig+3-2
......@@ -5,8 +5,9 @@
55// - sinh(nan) = nan
66
77const builtin = @import("builtin");
8const math = @import("index.zig");
9const assert = @import("../debug.zig").assert;
8const std = @import("../index.zig");
9const math = std.math;
10const assert = std.debug.assert;
1011const expo2 = @import("expo2.zig").expo2;
1112
1213pub fn tanh(x: var) -> @typeOf(x) {
std/math/trunc.zig+3-2
......@@ -4,8 +4,9 @@
44// - trunc(+-inf) = +-inf
55// - trunc(nan) = nan
66
7const math = @import("index.zig");
8const assert = @import("../debug.zig").assert;
7const std = @import("../index.zig");
8const math = std.math;
9const assert = std.debug.assert;
910
1011pub fn trunc(x: var) -> @typeOf(x) {
1112 const T = @typeOf(x);
std/mem.zig+3-2
......@@ -1,6 +1,7 @@
1const debug = @import("debug.zig");
1const std = @import("index.zig");
2const debug = std.debug;
23const assert = debug.assert;
3const math = @import("math/index.zig");
4const math = std.math;
45const builtin = @import("builtin");
56
67error OutOfMemory;
std/net.zig+4-3
......@@ -1,6 +1,7 @@
1const linux = @import("os/linux.zig");
2const assert = @import("debug.zig").assert;
3const endian = @import("endian.zig");
1const std = @import("index.zig");
2const linux = std.os.linux;
3const assert = std.debug.assert;
4const endian = std.endian;
45
56error SigInterrupt;
67error Io;
std/os/darwin.zig+3-2
......@@ -1,5 +1,6 @@
1const c = @import("../c/index.zig");
2const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const c = std.c;
3const assert = std.debug.assert;
34
45pub use @import("darwin_errno.zig");
56
std/os/index.zig+11-10
......@@ -1,3 +1,4 @@
1const std = @import("../index.zig");
12const builtin = @import("builtin");
23const Os = builtin.Os;
34const is_windows = builtin.os == Os.windows;
......@@ -37,22 +38,22 @@ pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock;
3738
3839pub const FileHandle = if (is_windows) windows.HANDLE else i32;
3940
40const debug = @import("../debug.zig");
41const debug = std.debug;
4142const assert = debug.assert;
4243
43const c = @import("../c/index.zig");
44const c = std.c;
4445
45const mem = @import("../mem.zig");
46const mem = std.mem;
4647const Allocator = mem.Allocator;
4748
48const BufMap = @import("../buf_map.zig").BufMap;
49const cstr = @import("../cstr.zig");
49const BufMap = std.BufMap;
50const cstr = std.cstr;
5051
51const io = @import("../io.zig");
52const base64 = @import("../base64.zig");
53const ArrayList = @import("../array_list.zig").ArrayList;
54const Buffer = @import("../buffer.zig").Buffer;
55const math = @import("../index.zig").math;
52const io = std.io;
53const base64 = std.base64;
54const ArrayList = std.ArrayList;
55const Buffer = std.Buffer;
56const math = std.math;
5657
5758error SystemResources;
5859error AccessDenied;
std/os/linux.zig+2-1
......@@ -1,4 +1,5 @@
1const assert = @import("../debug.zig").assert;
1const std = @import("../index.zig");
2const assert = std.debug.assert;
23const builtin = @import("builtin");
34const arch = switch (builtin.arch) {
45 builtin.Arch.x86_64 => @import("linux_x86_64.zig"),
std/os/path.zig+7-7
......@@ -1,16 +1,16 @@
1const std = @import("../index.zig");
12const builtin = @import("builtin");
23const Os = builtin.Os;
3const debug = @import("../debug.zig");
4const debug = std.debug;
45const assert = debug.assert;
5const mem = @import("../mem.zig");
6const fmt = @import("../fmt/index.zig");
6const mem = std.mem;
7const fmt = std.fmt;
78const Allocator = mem.Allocator;
8const os = @import("index.zig");
9const math = @import("../math/index.zig");
9const os = std.os;
10const math = std.math;
1011const posix = os.posix;
1112const windows = os.windows;
12const c = @import("../c/index.zig");
13const cstr = @import("../cstr.zig");
13const cstr = std.cstr;
1414
1515pub const sep_windows = '\\';
1616pub const sep_posix = '/';
std/rand.zig+4-3
......@@ -1,8 +1,9 @@
1const std = @import("index.zig");
12const builtin = @import("builtin");
2const assert = @import("debug.zig").assert;
3const assert = std.debug.assert;
34const rand_test = @import("rand_test.zig");
4const mem = @import("mem.zig");
5const math = @import("math/index.zig");
5const mem = std.mem;
6const math = std.math;
67
78pub const MT19937_32 = MersenneTwister(
89 u32, 624, 397, 31,
std/special/compiler_rt/fixunsdfdi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunsdfdi(a: f64, expected: u64) {
55 const x = __fixunsdfdi(a);
std/special/compiler_rt/fixunsdfsi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunsdfsi(a: f64, expected: u32) {
55 const x = __fixunsdfsi(a);
std/special/compiler_rt/fixunsdfti_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunsdfti(a: f64, expected: u128) {
55 const x = __fixunsdfti(a);
std/special/compiler_rt/fixunssfdi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunssfdi(a: f32, expected: u64) {
55 const x = __fixunssfdi(a);
std/special/compiler_rt/fixunssfsi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunssfsi(a: f32, expected: u32) {
55 const x = __fixunssfsi(a);
std/special/compiler_rt/fixunssfti_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunssfti = @import("fixunssfti.zig").__fixunssfti;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunssfti(a: f32, expected: u128) {
55 const x = __fixunssfti(a);
std/special/compiler_rt/fixunstfdi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunstfdi(a: f128, expected: u64) {
55 const x = __fixunstfdi(a);
std/special/compiler_rt/fixunstfsi_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunstfsi(a: f128, expected: u32) {
55 const x = __fixunstfsi(a);
std/special/compiler_rt/fixunstfti_test.zig+1-1
......@@ -1,5 +1,5 @@
11const __fixunstfti = @import("fixunstfti.zig").__fixunstfti;
2const assert = @import("../../debug.zig").assert;
2const assert = @import("../../index.zig").debug.assert;
33
44fn test__fixunstfti(a: f128, expected: u128) {
55 const x = __fixunstfti(a);
std/special/compiler_rt/index.zig+1-1
......@@ -68,7 +68,7 @@ comptime {
6868 }
6969}
7070
71const assert = @import("../../debug.zig").assert;
71const assert = @import("../../index.zig").debug.assert;
7272
7373const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4;
7474
test/cases/union.zig+15
......@@ -220,3 +220,18 @@ fn assertIsTheUnion2Item1(value: &const TheUnion2) {
220220 assert(*value == TheUnion2.Item1);
221221}
222222
223
224pub const PackThis = union(enum) {
225 Invalid: bool,
226 StringLiteral: u2,
227};
228
229test "constant packed union" {
230 testConstPackedUnion([]PackThis {
231 PackThis { .StringLiteral = 1 },
232 });
233}
234
235fn testConstPackedUnion(expected_tokens: []const PackThis) {
236 assert(expected_tokens[0].StringLiteral == 1);
237}