| author | |
| committer | |
| log | 6bfaf262d5a1d18482a813c7022ffb03a18f52a8 |
| tree | 7f432e8f386aed17df3f1bccdff34ec58b3ff2af |
| parent | 8b716f941dbd43936a994a008aec9cd21d0b08f2 |
| parent | 08dd1b553b37de24eaf24a37558b0f9993d4ca42 |
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 | ... | @@ -49,6 +49,8 @@ option(ZIG_FORCE_EXTERNAL_LLD "If your system has the LLD patches use it instead |
| 49 | find_package(llvm) | 49 | find_package(llvm) |
| 50 | find_package(clang) | 50 | find_package(clang) |
| 51 | 51 | ||
| 52 | set(ZIG_CPP_LIB_DIR "${CMAKE_BINARY_DIR}/zig_cpp") | ||
| 53 | |||
| 52 | if(ZIG_FORCE_EXTERNAL_LLD) | 54 | if(ZIG_FORCE_EXTERNAL_LLD) |
| 53 | find_package(lld) | 55 | find_package(lld) |
| 54 | include_directories(${LLVM_INCLUDE_DIRS}) | 56 | include_directories(${LLVM_INCLUDE_DIRS}) |
| ... | @@ -192,6 +194,7 @@ else() | ... | @@ -192,6 +194,7 @@ else() |
| 192 | embedded_lld_coff | 194 | embedded_lld_coff |
| 193 | embedded_lld_lib | 195 | embedded_lld_lib |
| 194 | ) | 196 | ) |
| 197 | install(TARGETS embedded_lld_elf embedded_lld_coff embedded_lld_lib DESTINATION "${ZIG_CPP_LIB_DIR}") | ||
| 195 | endif() | 198 | endif() |
| 196 | 199 | ||
| 197 | # No patches have been applied to SoftFloat-3d | 200 | # No patches have been applied to SoftFloat-3d |
| ... | @@ -345,6 +348,8 @@ set(ZIG_SOURCES | ... | @@ -345,6 +348,8 @@ set(ZIG_SOURCES |
| 345 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" | 348 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" |
| 346 | "${CMAKE_SOURCE_DIR}/src/util.cpp" | 349 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 347 | "${CMAKE_SOURCE_DIR}/src/translate_c.cpp" | 350 | "${CMAKE_SOURCE_DIR}/src/translate_c.cpp" |
| 351 | ) | ||
| 352 | set(ZIG_CPP_SOURCES | ||
| 348 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" | 353 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" |
| 349 | ) | 354 | ) |
| 350 | 355 | ||
| ... | @@ -390,6 +395,11 @@ if(ZIG_TEST_COVERAGE) | ... | @@ -390,6 +395,11 @@ if(ZIG_TEST_COVERAGE) |
| 390 | set(EXE_LDFLAGS "${EXE_LDFLAGS} -fprofile-arcs -ftest-coverage") | 395 | set(EXE_LDFLAGS "${EXE_LDFLAGS} -fprofile-arcs -ftest-coverage") |
| 391 | endif() | 396 | endif() |
| 392 | 397 | ||
| 398 | add_library(zig_cpp STATIC ${ZIG_CPP_SOURCES}) | ||
| 399 | set_target_properties(zig_cpp PROPERTIES | ||
| 400 | COMPILE_FLAGS ${EXE_CFLAGS} | ||
| 401 | ) | ||
| 402 | |||
| 393 | add_executable(zig ${ZIG_SOURCES}) | 403 | add_executable(zig ${ZIG_SOURCES}) |
| 394 | set_target_properties(zig PROPERTIES | 404 | set_target_properties(zig PROPERTIES |
| 395 | COMPILE_FLAGS ${EXE_CFLAGS} | 405 | COMPILE_FLAGS ${EXE_CFLAGS} |
| ... | @@ -397,6 +407,7 @@ set_target_properties(zig PROPERTIES | ... | @@ -397,6 +407,7 @@ set_target_properties(zig PROPERTIES |
| 397 | ) | 407 | ) |
| 398 | 408 | ||
| 399 | target_link_libraries(zig LINK_PUBLIC | 409 | target_link_libraries(zig LINK_PUBLIC |
| 410 | zig_cpp | ||
| 400 | ${SOFTFLOAT_LIBRARIES} | 411 | ${SOFTFLOAT_LIBRARIES} |
| 401 | ${CLANG_LIBRARIES} | 412 | ${CLANG_LIBRARIES} |
| 402 | ${LLD_LIBRARIES} | 413 | ${LLD_LIBRARIES} |
| ... | @@ -407,6 +418,7 @@ if(MSVC OR MINGW) | ... | @@ -407,6 +418,7 @@ if(MSVC OR MINGW) |
| 407 | target_link_libraries(zig LINK_PUBLIC version) | 418 | target_link_libraries(zig LINK_PUBLIC version) |
| 408 | endif() | 419 | endif() |
| 409 | install(TARGETS zig DESTINATION bin) | 420 | install(TARGETS zig DESTINATION bin) |
| 421 | install(TARGETS zig_cpp DESTINATION "${ZIG_CPP_LIB_DIR}") | ||
| 410 | 422 | ||
| 411 | install(FILES "${CMAKE_SOURCE_DIR}/c_headers/__clang_cuda_builtin_vars.h" DESTINATION "${C_HEADERS_DEST}") | 423 | install(FILES "${CMAKE_SOURCE_DIR}/c_headers/__clang_cuda_builtin_vars.h" DESTINATION "${C_HEADERS_DEST}") |
| 412 | install(FILES "${CMAKE_SOURCE_DIR}/c_headers/__clang_cuda_cmath.h" DESTINATION "${C_HEADERS_DEST}") | 424 | install(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} | ... | @@ -516,7 +528,8 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/c/index.zig" DESTINATION "${ZIG_STD_DEST} |
| 516 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/linux.zig" DESTINATION "${ZIG_STD_DEST}/c") | 528 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/linux.zig" DESTINATION "${ZIG_STD_DEST}/c") |
| 517 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/windows.zig" DESTINATION "${ZIG_STD_DEST}/c") | 529 | install(FILES "${CMAKE_SOURCE_DIR}/std/c/windows.zig" DESTINATION "${ZIG_STD_DEST}/c") |
| 518 | install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}") | 530 | install(FILES "${CMAKE_SOURCE_DIR}/std/cstr.zig" DESTINATION "${ZIG_STD_DEST}") |
| 519 | install(FILES "${CMAKE_SOURCE_DIR}/std/debug.zig" DESTINATION "${ZIG_STD_DEST}") | 531 | install(FILES "${CMAKE_SOURCE_DIR}/std/debug/index.zig" DESTINATION "${ZIG_STD_DEST}/debug") |
| 532 | install(FILES "${CMAKE_SOURCE_DIR}/std/debug/failing_allocator.zig" DESTINATION "${ZIG_STD_DEST}/debug") | ||
| 520 | install(FILES "${CMAKE_SOURCE_DIR}/std/dwarf.zig" DESTINATION "${ZIG_STD_DEST}") | 533 | install(FILES "${CMAKE_SOURCE_DIR}/std/dwarf.zig" DESTINATION "${ZIG_STD_DEST}") |
| 521 | install(FILES "${CMAKE_SOURCE_DIR}/std/elf.zig" DESTINATION "${ZIG_STD_DEST}") | 534 | install(FILES "${CMAKE_SOURCE_DIR}/std/elf.zig" DESTINATION "${ZIG_STD_DEST}") |
| 522 | install(FILES "${CMAKE_SOURCE_DIR}/std/empty.zig" DESTINATION "${ZIG_STD_DEST}") | 535 | install(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 | ... | @@ -618,16 +631,3 @@ install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/udivti3.zig" DESTINAT |
| 618 | install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/umodti3.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") | 631 | install(FILES "${CMAKE_SOURCE_DIR}/std/special/compiler_rt/umodti3.zig" DESTINATION "${ZIG_STD_DEST}/special/compiler_rt") |
| 619 | install(FILES "${CMAKE_SOURCE_DIR}/std/special/panic.zig" DESTINATION "${ZIG_STD_DEST}/special") | 632 | install(FILES "${CMAKE_SOURCE_DIR}/std/special/panic.zig" DESTINATION "${ZIG_STD_DEST}/special") |
| 620 | install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special") | 633 | install(FILES "${CMAKE_SOURCE_DIR}/std/special/test_runner.zig" DESTINATION "${ZIG_STD_DEST}/special") |
| 621 | |||
| 622 | if (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 | ) | ||
| 632 | endif() | ||
| 633 |
README.md+10-20| ... | @@ -26,7 +26,7 @@ clarity. | ... | @@ -26,7 +26,7 @@ clarity. |
| 26 | always compiled against statically in source form. Compile units do not | 26 | always compiled against statically in source form. Compile units do not |
| 27 | depend on libc unless explicitly linked. | 27 | depend on libc unless explicitly linked. |
| 28 | * Nullable type instead of null pointers. | 28 | * Nullable type instead of null pointers. |
| 29 | * Tagged union type instead of raw unions. | 29 | * Safe unions, tagged unions, and C ABI compatible unions. |
| 30 | * Generics so that one can write efficient data structures that work for any | 30 | * Generics so that one can write efficient data structures that work for any |
| 31 | data type. | 31 | data type. |
| 32 | * No header files required. Top level declarations are entirely | 32 | * No header files required. Top level declarations are entirely |
| ... | @@ -35,7 +35,7 @@ clarity. | ... | @@ -35,7 +35,7 @@ clarity. |
| 35 | * Partial compile-time function evaluation with eliminates the need for | 35 | * Partial compile-time function evaluation with eliminates the need for |
| 36 | a preprocessor or macros. | 36 | a preprocessor or macros. |
| 37 | * The binaries produced by Zig have complete debugging information so you can, | 37 | * 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. |
| 39 | * Built-in unit tests with `zig test`. | 39 | * Built-in unit tests with `zig test`. |
| 40 | * Friendly toward package maintainers. Reproducible build, bootstrapping | 40 | * Friendly toward package maintainers. Reproducible build, bootstrapping |
| 41 | process carefully documented. Issues filed by package maintainers are | 41 | process carefully documented. Issues filed by package maintainers are |
| ... | @@ -78,10 +78,10 @@ that counts as "freestanding" for the purposes of this table. | ... | @@ -78,10 +78,10 @@ that counts as "freestanding" for the purposes of this table. |
| 78 | 78 | ||
| 79 | ### Wanted: Windows Developers | 79 | ### Wanted: Windows Developers |
| 80 | 80 | ||
| 81 | Help get the tests passing on Windows, flesh out the standard library for | 81 | Flesh out the standard library for Windows, streamline Zig installation and |
| 82 | Windows, streamline Zig installation and distribution for Windows. Work with | 82 | distribution for Windows. Work with LLVM and LLD teams to improve |
| 83 | LLVM and LLD teams to improve PDB/CodeView/MSVC debugging. Implement stack traces | 83 | PDB/CodeView/MSVC debugging. Implement stack traces for Windows in the MinGW |
| 84 | for Windows in the MinGW environment and the MSVC environment. | 84 | environment and the MSVC environment. |
| 85 | 85 | ||
| 86 | ### Wanted: MacOS and iOS Developers | 86 | ### Wanted: MacOS and iOS Developers |
| 87 | 87 | ||
| ... | @@ -178,6 +178,10 @@ Dependencies are the same as Stage 1, except now you have a working zig compiler | ... | @@ -178,6 +178,10 @@ Dependencies are the same as Stage 1, except now you have a working zig compiler |
| 178 | bin/zig build --build-file ../build.zig --prefix $(pwd)/stage2 install | 178 | bin/zig build --build-file ../build.zig --prefix $(pwd)/stage2 install |
| 179 | ``` | 179 | ``` |
| 180 | 180 | ||
| 181 | This produces `./stage2/bin/zig` which can be used for testing and development. | ||
| 182 | Once it is feature complete, it will be used to build stage 3 - the final compiler | ||
| 183 | binary. | ||
| 184 | |||
| 181 | ### Stage 3: Rebuild Self-Hosted Zig Using the Self-Hosted Compiler | 185 | ### Stage 3: Rebuild Self-Hosted Zig Using the Self-Hosted Compiler |
| 182 | 186 | ||
| 183 | This is the actual compiler binary that we will install to the system. | 187 | This 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. | ... | @@ -194,20 +198,6 @@ This is the actual compiler binary that we will install to the system. |
| 194 | ./stage2/bin/zig build --build-file ../build.zig install -Drelease-fast | 198 | ./stage2/bin/zig build --build-file ../build.zig install -Drelease-fast |
| 195 | ``` | 199 | ``` |
| 196 | 200 | ||
| 197 | ### Test Coverage | ||
| 198 | |||
| 199 | To see test coverage in Zig, configure with `-DZIG_TEST_COVERAGE=ON` as an | ||
| 200 | additional parameter to the Debug build. | ||
| 201 | |||
| 202 | You must have `lcov` installed and available. | ||
| 203 | |||
| 204 | Then `make coverage`. | ||
| 205 | |||
| 206 | With GCC you will get a nice HTML view of the coverage data. With clang, | ||
| 207 | the last step will fail, but you can execute | ||
| 208 | `llvm-cov gcov $(find CMakeFiles/ -name "*.gcda")` and then inspect the | ||
| 209 | produced .gcov files. | ||
| 210 | |||
| 211 | ### Related Projects | 201 | ### Related Projects |
| 212 | 202 | ||
| 213 | * [zig-mode](https://github.com/AndreaOrru/zig-mode) - Emacs integration | 203 | * [zig-mode](https://github.com/AndreaOrru/zig-mode) - Emacs integration |
build.zig+30-2| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | const builtin = @import("builtin"); | ||
| 1 | const std = @import("std"); | 2 | const std = @import("std"); |
| 2 | const Builder = std.build.Builder; | 3 | const Builder = std.build.Builder; |
| 3 | const tests = @import("test/tests.zig"); | 4 | const tests = @import("test/tests.zig"); |
| ... | @@ -33,11 +34,32 @@ pub fn build(b: &Builder) { | ... | @@ -33,11 +34,32 @@ pub fn build(b: &Builder) { |
| 33 | docs_step.dependOn(&docgen_home_cmd.step); | 34 | docs_step.dependOn(&docgen_home_cmd.step); |
| 34 | 35 | ||
| 35 | if (findLLVM(b)) |llvm| { | 36 | 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 | |||
| 36 | var exe = b.addExecutable("zig", "src-self-hosted/main.zig"); | 43 | var exe = b.addExecutable("zig", "src-self-hosted/main.zig"); |
| 37 | exe.setBuildMode(mode); | 44 | 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"); | ||
| 39 | dependOnLib(exe, llvm); | 51 | dependOnLib(exe, llvm); |
| 40 | 52 | ||
| 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 | |||
| 41 | b.default_step.dependOn(&exe.step); | 63 | b.default_step.dependOn(&exe.step); |
| 42 | b.default_step.dependOn(docs_step); | 64 | b.default_step.dependOn(docs_step); |
| 43 | 65 | ||
| ... | @@ -91,6 +113,11 @@ fn dependOnLib(lib_exe_obj: &std.build.LibExeObjStep, dep: &const LibraryDep) { | ... | @@ -91,6 +113,11 @@ fn dependOnLib(lib_exe_obj: &std.build.LibExeObjStep, dep: &const LibraryDep) { |
| 91 | } | 113 | } |
| 92 | } | 114 | } |
| 93 | 115 | ||
| 116 | fn 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 | |||
| 94 | const LibraryDep = struct { | 121 | const LibraryDep = struct { |
| 95 | libdirs: ArrayList([]const u8), | 122 | libdirs: ArrayList([]const u8), |
| 96 | libs: ArrayList([]const u8), | 123 | libs: ArrayList([]const u8), |
| ... | @@ -172,7 +199,8 @@ pub fn installStdLib(b: &Builder) { | ... | @@ -172,7 +199,8 @@ pub fn installStdLib(b: &Builder) { |
| 172 | "c/linux.zig", | 199 | "c/linux.zig", |
| 173 | "c/windows.zig", | 200 | "c/windows.zig", |
| 174 | "cstr.zig", | 201 | "cstr.zig", |
| 175 | "debug.zig", | 202 | "debug/failing_allocator.zig", |
| 203 | "debug/index.zig", | ||
| 176 | "dwarf.zig", | 204 | "dwarf.zig", |
| 177 | "elf.zig", | 205 | "elf.zig", |
| 178 | "empty.zig", | 206 | "empty.zig", |
doc/langref.html.in+9| ... | @@ -291,6 +291,15 @@ pub fn main() -> %void { | ... | @@ -291,6 +291,15 @@ pub fn main() -> %void { |
| 291 | <li><a href="#errors">Errors</a></li> | 291 | <li><a href="#errors">Errors</a></li> |
| 292 | <li><a href="#root-source-file">Root Source File</a></li> | 292 | <li><a href="#root-source-file">Root Source File</a></li> |
| 293 | </ul> | 293 | </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> | ||
| 294 | <h2 id="values">Values</h2> | 303 | <h2 id="values">Values</h2> |
| 295 | <pre><code class="zig">const warn = @import("std").debug.warn; | 304 | <pre><code class="zig">const warn = @import("std").debug.warn; |
| 296 | const os = @import("std").os; | 305 | const os = @import("std").os; |
src-self-hosted/c.zig+2-5| ... | @@ -1,7 +1,4 @@ | ... | @@ -1,7 +1,4 @@ |
| 1 | pub use @cImport({ | 1 | pub use @cImport({ |
| 2 | @cInclude("llvm-c/Core.h"); | 2 | @cInclude("config.h"); |
| 3 | @cInclude("llvm-c/Analysis.h"); | 3 | @cInclude("zig_llvm.h"); |
| 4 | @cInclude("llvm-c/Target.h"); | ||
| 5 | @cInclude("llvm-c/Initialization.h"); | ||
| 6 | @cInclude("llvm-c/TargetMachine.h"); | ||
| 7 | }); | 4 | }); |
src-self-hosted/ir.zig created+112| ... | @@ -0,0 +1,112 @@ | ||
| 1 | const Scope = @import("scope.zig").Scope; | ||
| 2 | |||
| 3 | pub 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; | ... | @@ -12,6 +12,7 @@ const ErrColor = Module.ErrColor; |
| 12 | const Emit = Module.Emit; | 12 | const Emit = Module.Emit; |
| 13 | const builtin = @import("builtin"); | 13 | const builtin = @import("builtin"); |
| 14 | const ArrayList = std.ArrayList; | 14 | const ArrayList = std.ArrayList; |
| 15 | const c = @import("c.zig"); | ||
| 15 | 16 | ||
| 16 | error InvalidCommandLineArguments; | 17 | error InvalidCommandLineArguments; |
| 17 | error ZigLibDirNotFound; | 18 | error ZigLibDirNotFound; |
| ... | @@ -462,7 +463,11 @@ pub fn main2() -> %void { | ... | @@ -462,7 +463,11 @@ pub fn main2() -> %void { |
| 462 | else => unreachable, | 463 | else => unreachable, |
| 463 | } | 464 | } |
| 464 | }, | 465 | }, |
| 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 | }, | ||
| 466 | Cmd.Targets => @panic("TODO zig targets"), | 471 | Cmd.Targets => @panic("TODO zig targets"), |
| 467 | } | 472 | } |
| 468 | } | 473 | } |
src-self-hosted/module.zig+7| ... | @@ -199,6 +199,13 @@ pub const Module = struct { | ... | @@ -199,6 +199,13 @@ pub const Module = struct { |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | pub fn build(self: &Module) -> %void { | 201 | 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 | |||
| 202 | const root_src_path = self.root_src_path ?? @panic("TODO handle null root src path"); | 209 | const root_src_path = self.root_src_path ?? @panic("TODO handle null root src path"); |
| 203 | const root_src_real_path = os.path.real(self.allocator, root_src_path) %% |err| { | 210 | const root_src_real_path = os.path.real(self.allocator, root_src_path) %% |err| { |
| 204 | %return printError("unable to open '{}': {}", root_src_path, err); | 211 | %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) { | ... | @@ -1119,18 +1119,24 @@ fn testCanonical(source: []const u8) { |
| 1119 | break :x failing_allocator.index; | 1119 | break :x failing_allocator.index; |
| 1120 | }; | 1120 | }; |
| 1121 | 1121 | ||
| 1122 | // TODO make this pass | 1122 | var fail_index: usize = 0; |
| 1123 | //var fail_index = needed_alloc_count; | 1123 | while (fail_index < needed_alloc_count) : (fail_index += 1) { |
| 1124 | //while (fail_index != 0) { | 1124 | var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]); |
| 1125 | // fail_index -= 1; | 1125 | var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index); |
| 1126 | // var fixed_allocator = mem.FixedBufferAllocator.init(fixed_buffer_mem[0..]); | 1126 | if (testParse(source, &failing_allocator.allocator)) |_| { |
| 1127 | // var failing_allocator = std.debug.FailingAllocator.init(&fixed_allocator.allocator, fail_index); | 1127 | @panic("non-deterministic memory usage"); |
| 1128 | // if (testParse(source, &failing_allocator.allocator)) |_| { | 1128 | } else |err| { |
| 1129 | // @panic("non-deterministic memory usage"); | 1129 | assert(err == error.OutOfMemory); |
| 1130 | // } else |err| { | 1130 | // TODO make this pass |
| 1131 | // assert(err == error.OutOfMemory); | 1131 | //if (failing_allocator.allocated_bytes != failing_allocator.freed_bytes) { |
| 1132 | // } | 1132 | // warn("\nfail_index: {}/{}\nallocated bytes: {}\nfreed bytes: {}\nallocations: {}\ndeallocations: {}\n", |
| 1133 | //} | 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 | } | ||
| 1134 | } | 1140 | } |
| 1135 | 1141 | ||
| 1136 | test "zig fmt" { | 1142 | test "zig fmt" { |
src-self-hosted/scope.zig created+16| ... | @@ -0,0 +1,16 @@ | ||
| 1 | pub 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 { | ... | @@ -70,6 +70,7 @@ pub const Token = struct { |
| 70 | Identifier, | 70 | Identifier, |
| 71 | StringLiteral: StrLitKind, | 71 | StringLiteral: StrLitKind, |
| 72 | Eof, | 72 | Eof, |
| 73 | NoEolAtEof, | ||
| 73 | Builtin, | 74 | Builtin, |
| 74 | Bang, | 75 | Bang, |
| 75 | Equal, | 76 | Equal, |
| ... | @@ -139,6 +140,8 @@ pub const Token = struct { | ... | @@ -139,6 +140,8 @@ pub const Token = struct { |
| 139 | pub const Tokenizer = struct { | 140 | pub const Tokenizer = struct { |
| 140 | buffer: []const u8, | 141 | buffer: []const u8, |
| 141 | index: usize, | 142 | index: usize, |
| 143 | actual_file_end: usize, | ||
| 144 | pending_invalid_token: ?Token, | ||
| 142 | 145 | ||
| 143 | pub const Location = struct { | 146 | pub const Location = struct { |
| 144 | line: usize, | 147 | line: usize, |
| ... | @@ -177,9 +180,17 @@ pub const Tokenizer = struct { | ... | @@ -177,9 +180,17 @@ pub const Tokenizer = struct { |
| 177 | } | 180 | } |
| 178 | 181 | ||
| 179 | pub fn init(buffer: []const u8) -> Tokenizer { | 182 | 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 | |||
| 180 | return Tokenizer { | 189 | return Tokenizer { |
| 181 | .buffer = buffer, | 190 | .buffer = buffer[0..source_len], |
| 182 | .index = 0, | 191 | .index = 0, |
| 192 | .actual_file_end = buffer.len, | ||
| 193 | .pending_invalid_token = null, | ||
| 183 | }; | 194 | }; |
| 184 | } | 195 | } |
| 185 | 196 | ||
| ... | @@ -207,6 +218,10 @@ pub const Tokenizer = struct { | ... | @@ -207,6 +218,10 @@ pub const Tokenizer = struct { |
| 207 | }; | 218 | }; |
| 208 | 219 | ||
| 209 | pub fn next(self: &Tokenizer) -> Token { | 220 | pub fn next(self: &Tokenizer) -> Token { |
| 221 | if (self.pending_invalid_token) |token| { | ||
| 222 | self.pending_invalid_token = null; | ||
| 223 | return token; | ||
| 224 | } | ||
| 210 | var state = State.Start; | 225 | var state = State.Start; |
| 211 | var result = Token { | 226 | var result = Token { |
| 212 | .id = Token.Id.Eof, | 227 | .id = Token.Id.Eof, |
| ... | @@ -352,7 +367,7 @@ pub const Tokenizer = struct { | ... | @@ -352,7 +367,7 @@ pub const Tokenizer = struct { |
| 352 | break; | 367 | break; |
| 353 | }, | 368 | }, |
| 354 | '\n' => break, // Look for this error later. | 369 | '\n' => break, // Look for this error later. |
| 355 | else => {}, | 370 | else => self.checkLiteralCharacter(), |
| 356 | }, | 371 | }, |
| 357 | 372 | ||
| 358 | State.StringLiteralBackslash => switch (c) { | 373 | State.StringLiteralBackslash => switch (c) { |
| ... | @@ -439,7 +454,7 @@ pub const Tokenizer = struct { | ... | @@ -439,7 +454,7 @@ pub const Tokenizer = struct { |
| 439 | .end = undefined, | 454 | .end = undefined, |
| 440 | }; | 455 | }; |
| 441 | }, | 456 | }, |
| 442 | else => {}, | 457 | else => self.checkLiteralCharacter(), |
| 443 | }, | 458 | }, |
| 444 | State.Zero => switch (c) { | 459 | State.Zero => switch (c) { |
| 445 | 'b', 'o', 'x' => { | 460 | 'b', 'o', 'x' => { |
| ... | @@ -497,13 +512,211 @@ pub const Tokenizer = struct { | ... | @@ -497,13 +512,211 @@ pub const Tokenizer = struct { |
| 497 | } | 512 | } |
| 498 | } | 513 | } |
| 499 | result.end = self.index; | 514 | 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 | } | ||
| 501 | return result; | 526 | return result; |
| 502 | } | 527 | } |
| 503 | 528 | ||
| 504 | pub fn getTokenSlice(self: &const Tokenizer, token: &const Token) -> []const u8 { | 529 | pub fn getTokenSlice(self: &const Tokenizer, token: &const Token) -> []const u8 { |
| 505 | return self.buffer[token.start..token.end]; | 530 | return self.buffer[token.start..token.end]; |
| 506 | } | 531 | } |
| 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 | } | ||
| 507 | }; | 601 | }; |
| 508 | 602 | ||
| 509 | 603 | ||
| 604 | |||
| 605 | test "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 | |||
| 618 | test "tokenizer - invalid token characters" { | ||
| 619 | testTokenize("#\n", []Token.Id{Token.Id.Invalid}); | ||
| 620 | testTokenize("`\n", []Token.Id{Token.Id.Invalid}); | ||
| 621 | } | ||
| 622 | |||
| 623 | test "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 | |||
| 639 | test "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 | |||
| 651 | test "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 | |||
| 676 | test "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 | |||
| 685 | test "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 | |||
| 706 | fn testTokenize(source: []const u8, expected_tokens: []const Token.Id) { | ||
| 707 | testTokenizeWithEol(source, expected_tokens, true); | ||
| 708 | } | ||
| 709 | fn 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 @@ | ... | @@ -10,7 +10,7 @@ |
| 10 | 10 | ||
| 11 | #include "list.hpp" | 11 | #include "list.hpp" |
| 12 | #include "buffer.hpp" | 12 | #include "buffer.hpp" |
| 13 | #include "zig_llvm.hpp" | 13 | #include "zig_llvm.h" |
| 14 | #include "hash_map.hpp" | 14 | #include "hash_map.hpp" |
| 15 | #include "errmsg.hpp" | 15 | #include "errmsg.hpp" |
| 16 | #include "bigint.hpp" | 16 | #include "bigint.hpp" |
src/analyze.cpp+1-1| ... | @@ -14,7 +14,7 @@ | ... | @@ -14,7 +14,7 @@ |
| 14 | #include "os.hpp" | 14 | #include "os.hpp" |
| 15 | #include "parser.hpp" | 15 | #include "parser.hpp" |
| 16 | #include "softfloat.hpp" | 16 | #include "softfloat.hpp" |
| 17 | #include "zig_llvm.hpp" | 17 | #include "zig_llvm.h" |
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | static const size_t default_backward_branch_quota = 1000; | 20 | static const size_t default_backward_branch_quota = 1000; |
src/codegen.cpp+20-8| ... | @@ -17,7 +17,7 @@ | ... | @@ -17,7 +17,7 @@ |
| 17 | #include "os.hpp" | 17 | #include "os.hpp" |
| 18 | #include "translate_c.hpp" | 18 | #include "translate_c.hpp" |
| 19 | #include "target.hpp" | 19 | #include "target.hpp" |
| 20 | #include "zig_llvm.hpp" | 20 | #include "zig_llvm.h" |
| 21 | 21 | ||
| 22 | #include <stdio.h> | 22 | #include <stdio.h> |
| 23 | #include <errno.h> | 23 | #include <errno.h> |
| ... | @@ -3705,12 +3705,24 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar | ... | @@ -3705,12 +3705,24 @@ static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *ar |
| 3705 | ConstParent *parent = &array_const_val->data.x_array.s_none.parent; | 3705 | ConstParent *parent = &array_const_val->data.x_array.s_none.parent; |
| 3706 | LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent); | 3706 | LLVMValueRef base_ptr = gen_parent_ptr(g, array_const_val, parent); |
| 3707 | 3707 | ||
| 3708 | TypeTableEntry *usize = g->builtin_types.entry_usize; | 3708 | LLVMTypeKind el_type = LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(base_ptr))); |
| 3709 | LLVMValueRef indices[] = { | 3709 | if (el_type == LLVMArrayTypeKind) { |
| 3710 | LLVMConstNull(usize->type_ref), | 3710 | TypeTableEntry *usize = g->builtin_types.entry_usize; |
| 3711 | LLVMConstInt(usize->type_ref, index, false), | 3711 | LLVMValueRef indices[] = { |
| 3712 | }; | 3712 | LLVMConstNull(usize->type_ref), |
| 3713 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); | 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 | } | ||
| 3714 | } | 3726 | } |
| 3715 | 3727 | ||
| 3716 | static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index) { | 3728 | static 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 | ... | @@ -3732,7 +3744,7 @@ static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *un |
| 3732 | TypeTableEntry *u32 = g->builtin_types.entry_u32; | 3744 | TypeTableEntry *u32 = g->builtin_types.entry_u32; |
| 3733 | LLVMValueRef indices[] = { | 3745 | LLVMValueRef indices[] = { |
| 3734 | LLVMConstNull(u32->type_ref), | 3746 | 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 |
| 3736 | }; | 3748 | }; |
| 3737 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); | 3749 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); |
| 3738 | } | 3750 | } |
src/config.h.in+4| ... | @@ -24,4 +24,8 @@ | ... | @@ -24,4 +24,8 @@ |
| 24 | // Only used for running tests before installing. | 24 | // Only used for running tests before installing. |
| 25 | #define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test" | 25 | #define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test" |
| 26 | 26 | ||
| 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 | |||
| 27 | #endif | 31 | #endif |
src/link.cpp+12-2| ... | @@ -351,6 +351,16 @@ static void coff_append_machine_arg(CodeGen *g, ZigList<const char *> *list) { | ... | @@ -351,6 +351,16 @@ static void coff_append_machine_arg(CodeGen *g, ZigList<const char *> *list) { |
| 351 | } | 351 | } |
| 352 | } | 352 | } |
| 353 | 353 | ||
| 354 | static 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 | |||
| 359 | static 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 | |||
| 354 | static void construct_linker_job_coff(LinkJob *lj) { | 364 | static void construct_linker_job_coff(LinkJob *lj) { |
| 355 | CodeGen *g = lj->codegen; | 365 | CodeGen *g = lj->codegen; |
| 356 | 366 | ||
| ... | @@ -515,7 +525,7 @@ static void construct_linker_job_coff(LinkJob *lj) { | ... | @@ -515,7 +525,7 @@ static void construct_linker_job_coff(LinkJob *lj) { |
| 515 | gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path)))); | 525 | gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path)))); |
| 516 | gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path)))); | 526 | gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path)))); |
| 517 | Buf diag = BUF_INIT; | 527 | 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)) { |
| 519 | fprintf(stderr, "%s\n", buf_ptr(&diag)); | 529 | fprintf(stderr, "%s\n", buf_ptr(&diag)); |
| 520 | exit(1); | 530 | exit(1); |
| 521 | } | 531 | } |
| ... | @@ -930,7 +940,7 @@ void codegen_link(CodeGen *g, const char *out_file) { | ... | @@ -930,7 +940,7 @@ void codegen_link(CodeGen *g, const char *out_file) { |
| 930 | Buf diag = BUF_INIT; | 940 | Buf diag = BUF_INIT; |
| 931 | 941 | ||
| 932 | codegen_add_time_event(g, "LLVM Link"); | 942 | 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)) { |
| 934 | fprintf(stderr, "%s\n", buf_ptr(&diag)); | 944 | fprintf(stderr, "%s\n", buf_ptr(&diag)); |
| 935 | exit(1); | 945 | exit(1); |
| 936 | } | 946 | } |
src/main.cpp+5| ... | @@ -266,6 +266,11 @@ static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) { | ... | @@ -266,6 +266,11 @@ static void add_package(CodeGen *g, CliPkg *cli_pkg, PackageTableEntry *pkg) { |
| 266 | } | 266 | } |
| 267 | 267 | ||
| 268 | int main(int argc, char **argv) { | 268 | int 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 | |||
| 269 | os_init(); | 274 | os_init(); |
| 270 | 275 | ||
| 271 | char *arg0 = argv[0]; | 276 | char *arg0 = argv[0]; |
src/os.hpp+1-1| ... | @@ -11,7 +11,7 @@ | ... | @@ -11,7 +11,7 @@ |
| 11 | #include "list.hpp" | 11 | #include "list.hpp" |
| 12 | #include "buffer.hpp" | 12 | #include "buffer.hpp" |
| 13 | #include "error.hpp" | 13 | #include "error.hpp" |
| 14 | #include "zig_llvm.hpp" | 14 | #include "zig_llvm.h" |
| 15 | 15 | ||
| 16 | #include <stdio.h> | 16 | #include <stdio.h> |
| 17 | #include <inttypes.h> | 17 | #include <inttypes.h> |
src/target.hpp+1-1| ... | @@ -8,7 +8,7 @@ | ... | @@ -8,7 +8,7 @@ |
| 8 | #ifndef ZIG_TARGET_HPP | 8 | #ifndef ZIG_TARGET_HPP |
| 9 | #define ZIG_TARGET_HPP | 9 | #define ZIG_TARGET_HPP |
| 10 | 10 | ||
| 11 | #include <zig_llvm.hpp> | 11 | #include <zig_llvm.h> |
| 12 | 12 | ||
| 13 | struct Buf; | 13 | struct Buf; |
| 14 | 14 |
src/util.hpp-2| ... | @@ -13,8 +13,6 @@ | ... | @@ -13,8 +13,6 @@ |
| 13 | #include <string.h> | 13 | #include <string.h> |
| 14 | #include <assert.h> | 14 | #include <assert.h> |
| 15 | 15 | ||
| 16 | #include <new> | ||
| 17 | |||
| 18 | #if defined(_MSC_VER) | 16 | #if defined(_MSC_VER) |
| 19 | 17 | ||
| 20 | #include <intrin.h> | 18 | #include <intrin.h> |
src/zig_llvm.cpp+65-29| ... | @@ -13,7 +13,7 @@ | ... | @@ -13,7 +13,7 @@ |
| 13 | * 3. Prevent C++ from infecting the rest of the project. | 13 | * 3. Prevent C++ from infecting the rest of the project. |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include "zig_llvm.hpp" | 16 | #include "zig_llvm.h" |
| 17 | 17 | ||
| 18 | #include <llvm/Analysis/TargetLibraryInfo.h> | 18 | #include <llvm/Analysis/TargetLibraryInfo.h> |
| 19 | #include <llvm/Analysis/TargetTransformInfo.h> | 19 | #include <llvm/Analysis/TargetTransformInfo.h> |
| ... | @@ -39,8 +39,35 @@ | ... | @@ -39,8 +39,35 @@ |
| 39 | 39 | ||
| 40 | #include <lld/Common/Driver.h> | 40 | #include <lld/Common/Driver.h> |
| 41 | 41 | ||
| 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 | |||
| 42 | using namespace llvm; | 52 | using namespace llvm; |
| 43 | 53 | ||
| 54 | template<typename T, typename... Args> | ||
| 55 | ATTRIBUTE_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 | |||
| 63 | template<typename T> | ||
| 64 | static inline void destroy(T * ptr) { | ||
| 65 | if (ptr != nullptr) { | ||
| 66 | ptr[0].~T(); | ||
| 67 | } | ||
| 68 | free(ptr); | ||
| 69 | } | ||
| 70 | |||
| 44 | void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R) { | 71 | void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R) { |
| 45 | initializeLoopStrengthReducePass(*unwrap(R)); | 72 | initializeLoopStrengthReducePass(*unwrap(R)); |
| 46 | } | 73 | } |
| ... | @@ -50,8 +77,7 @@ void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R) { | ... | @@ -50,8 +77,7 @@ void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R) { |
| 50 | } | 77 | } |
| 51 | 78 | ||
| 52 | char *ZigLLVMGetHostCPUName(void) { | 79 | char *ZigLLVMGetHostCPUName(void) { |
| 53 | std::string str = sys::getHostCPUName(); | 80 | return strdup((const char *)sys::getHostCPUName().bytes_begin()); |
| 54 | return strdup(str.c_str()); | ||
| 55 | } | 81 | } |
| 56 | 82 | ||
| 57 | char *ZigLLVMGetNativeFeatures(void) { | 83 | char *ZigLLVMGetNativeFeatures(void) { |
| ... | @@ -63,11 +89,11 @@ char *ZigLLVMGetNativeFeatures(void) { | ... | @@ -63,11 +89,11 @@ char *ZigLLVMGetNativeFeatures(void) { |
| 63 | features.AddFeature(F.first(), F.second); | 89 | features.AddFeature(F.first(), F.second); |
| 64 | } | 90 | } |
| 65 | 91 | ||
| 66 | return strdup(features.getString().c_str()); | 92 | return strdup((const char *)StringRef(features.getString()).bytes_begin()); |
| 67 | } | 93 | } |
| 68 | 94 | ||
| 69 | static void addDiscriminatorsPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { | 95 | static void addDiscriminatorsPass(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { |
| 70 | PM.add(createAddDiscriminatorsPass()); | 96 | PM.add(createAddDiscriminatorsPass()); |
| 71 | } | 97 | } |
| 72 | 98 | ||
| 73 | #ifndef NDEBUG | 99 | #ifndef NDEBUG |
| ... | @@ -82,7 +108,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM | ... | @@ -82,7 +108,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 82 | std::error_code EC; | 108 | std::error_code EC; |
| 83 | raw_fd_ostream dest(filename, EC, sys::fs::F_None); | 109 | raw_fd_ostream dest(filename, EC, sys::fs::F_None); |
| 84 | if (EC) { | 110 | if (EC) { |
| 85 | *error_message = strdup(EC.message().c_str()); | 111 | *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin()); |
| 86 | return true; | 112 | return true; |
| 87 | } | 113 | } |
| 88 | TargetMachine* target_machine = reinterpret_cast<TargetMachine*>(targ_machine_ref); | 114 | TargetMachine* target_machine = reinterpret_cast<TargetMachine*>(targ_machine_ref); |
| ... | @@ -90,7 +116,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM | ... | @@ -90,7 +116,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 90 | 116 | ||
| 91 | Module* module = unwrap(module_ref); | 117 | Module* module = unwrap(module_ref); |
| 92 | 118 | ||
| 93 | PassManagerBuilder *PMBuilder = new PassManagerBuilder(); | 119 | PassManagerBuilder *PMBuilder = create<PassManagerBuilder>(); |
| 94 | PMBuilder->OptLevel = target_machine->getOptLevel(); | 120 | PMBuilder->OptLevel = target_machine->getOptLevel(); |
| 95 | PMBuilder->SizeLevel = 0; | 121 | PMBuilder->SizeLevel = 0; |
| 96 | 122 | ||
| ... | @@ -123,7 +149,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM | ... | @@ -123,7 +149,7 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM |
| 123 | 149 | ||
| 124 | // Set up the per-function pass manager. | 150 | // Set up the per-function pass manager. |
| 125 | legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module); | 151 | legacy::FunctionPassManager FPM = legacy::FunctionPassManager(module); |
| 126 | FPM.add(new TargetLibraryInfoWrapperPass(tlii)); | 152 | FPM.add(create<TargetLibraryInfoWrapperPass>(tlii)); |
| 127 | FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); | 153 | FPM.add(createTargetTransformInfoWrapperPass(target_machine->getTargetIRAnalysis())); |
| 128 | if (assertions_on) { | 154 | if (assertions_on) { |
| 129 | FPM.add(createVerifierPass()); | 155 | FPM.add(createVerifierPass()); |
| ... | @@ -415,7 +441,10 @@ unsigned ZigLLVMTag_DW_union_type(void) { | ... | @@ -415,7 +441,10 @@ unsigned ZigLLVMTag_DW_union_type(void) { |
| 415 | } | 441 | } |
| 416 | 442 | ||
| 417 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) { | 443 | ZigLLVMDIBuilder *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); | ||
| 419 | return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder); | 448 | return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder); |
| 420 | } | 449 | } |
| 421 | 450 | ||
| ... | @@ -617,7 +646,7 @@ void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn_ref) { | ... | @@ -617,7 +646,7 @@ void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn_ref) { |
| 617 | func->setAttributes(new_attr_set); | 646 | func->setAttributes(new_attr_set); |
| 618 | } | 647 | } |
| 619 | 648 | ||
| 620 | void ZigLLVMParseCommandLineOptions(int argc, const char *const *argv) { | 649 | void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) { |
| 621 | llvm::cl::ParseCommandLineOptions(argc, argv); | 650 | llvm::cl::ParseCommandLineOptions(argc, argv); |
| 622 | } | 651 | } |
| 623 | 652 | ||
| ... | @@ -775,29 +804,35 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV | ... | @@ -775,29 +804,35 @@ LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLV |
| 775 | } | 804 | } |
| 776 | 805 | ||
| 777 | 806 | ||
| 778 | #include "buffer.hpp" | 807 | class 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 | |||
| 779 | 825 | ||
| 780 | bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag_buf) { | 826 | bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, |
| 827 | void (*append_diagnostic)(void *, const char *, size_t), void *context) | ||
| 828 | { | ||
| 781 | ArrayRef<const char *> array_ref_args(args, arg_count); | 829 | ArrayRef<const char *> array_ref_args(args, arg_count); |
| 782 | 830 | ||
| 783 | buf_resize(diag_buf, 0); | 831 | MyOStream diag(append_diagnostic, context); |
| 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); | ||
| 797 | 832 | ||
| 798 | switch (oformat) { | 833 | switch (oformat) { |
| 799 | case ZigLLVM_UnknownObjectFormat: | 834 | case ZigLLVM_UnknownObjectFormat: |
| 800 | zig_unreachable(); | 835 | assert(false); // unreachable |
| 801 | 836 | ||
| 802 | case ZigLLVM_COFF: | 837 | case ZigLLVM_COFF: |
| 803 | return lld::coff::link(array_ref_args, false, diag); | 838 | return lld::coff::link(array_ref_args, false, diag); |
| ... | @@ -809,7 +844,8 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_ | ... | @@ -809,7 +844,8 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_ |
| 809 | return lld::mach_o::link(array_ref_args, diag); | 844 | return lld::mach_o::link(array_ref_args, diag); |
| 810 | 845 | ||
| 811 | case ZigLLVM_Wasm: | 846 | case ZigLLVM_Wasm: |
| 812 | zig_panic("ZigLLDLink for Wasm"); | 847 | assert(false); // TODO ZigLLDLink for Wasm |
| 813 | } | 848 | } |
| 814 | zig_unreachable(); | 849 | assert(false); // unreachable |
| 850 | abort(); | ||
| 815 | } | 851 | } |
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 | |||
| 25 | struct ZigLLVMDIType; | ||
| 26 | struct ZigLLVMDIBuilder; | ||
| 27 | struct ZigLLVMDICompileUnit; | ||
| 28 | struct ZigLLVMDIScope; | ||
| 29 | struct ZigLLVMDIFile; | ||
| 30 | struct ZigLLVMDILexicalBlock; | ||
| 31 | struct ZigLLVMDISubprogram; | ||
| 32 | struct ZigLLVMDISubroutineType; | ||
| 33 | struct ZigLLVMDILocalVariable; | ||
| 34 | struct ZigLLVMDIGlobalVariable; | ||
| 35 | struct ZigLLVMDILocation; | ||
| 36 | struct ZigLLVMDIEnumerator; | ||
| 37 | struct ZigLLVMInsertionPoint; | ||
| 38 | |||
| 39 | ZIG_EXTERN_C void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R); | ||
| 40 | ZIG_EXTERN_C void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R); | ||
| 41 | |||
| 42 | /// Caller must free memory. | ||
| 43 | ZIG_EXTERN_C char *ZigLLVMGetHostCPUName(void); | ||
| 44 | ZIG_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. | ||
| 48 | enum ZigLLVM_EmitOutputType { | ||
| 49 | ZigLLVM_EmitAssembly, | ||
| 50 | ZigLLVM_EmitBinary, | ||
| 51 | ZigLLVM_EmitLLVMIr, | ||
| 52 | }; | ||
| 53 | |||
| 54 | ZIG_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 | |||
| 57 | enum ZigLLVM_FnInline { | ||
| 58 | ZigLLVM_FnInlineAuto, | ||
| 59 | ZigLLVM_FnInlineAlways, | ||
| 60 | ZigLLVM_FnInlineNever, | ||
| 61 | }; | ||
| 62 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, | ||
| 63 | unsigned NumArgs, unsigned CC, enum ZigLLVM_FnInline fn_inline, const char *Name); | ||
| 64 | |||
| 65 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, | ||
| 66 | LLVMValueRef new_val, LLVMAtomicOrdering success_ordering, | ||
| 67 | LLVMAtomicOrdering failure_ordering); | ||
| 68 | |||
| 69 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, | ||
| 70 | const char *name); | ||
| 71 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, | ||
| 72 | const char *name); | ||
| 73 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, | ||
| 74 | const char *name); | ||
| 75 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, | ||
| 76 | const char *name); | ||
| 77 | |||
| 78 | ZIG_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 | |||
| 81 | ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugBasicType(struct ZigLLVMDIBuilder *dibuilder, const char *name, | ||
| 82 | uint64_t size_in_bits, unsigned encoding); | ||
| 83 | |||
| 84 | ZIG_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 | |||
| 88 | ZIG_EXTERN_C struct ZigLLVMDIEnumerator *ZigLLVMCreateDebugEnumerator(struct ZigLLVMDIBuilder *dibuilder, | ||
| 89 | const char *name, int64_t val); | ||
| 90 | |||
| 91 | ZIG_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 | |||
| 96 | ZIG_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 | |||
| 102 | ZIG_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 | |||
| 107 | ZIG_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 | |||
| 112 | ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateReplaceableCompositeType(struct ZigLLVMDIBuilder *dibuilder, | ||
| 113 | unsigned tag, const char *name, struct ZigLLVMDIScope *scope, struct ZigLLVMDIFile *file, unsigned line); | ||
| 114 | |||
| 115 | ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateDebugForwardDeclType(struct ZigLLVMDIBuilder *dibuilder, unsigned tag, | ||
| 116 | const char *name, struct ZigLLVMDIScope *scope, struct ZigLLVMDIFile *file, unsigned line); | ||
| 117 | |||
| 118 | ZIG_EXTERN_C void ZigLLVMReplaceTemporary(struct ZigLLVMDIBuilder *dibuilder, struct ZigLLVMDIType *type, | ||
| 119 | struct ZigLLVMDIType *replacement); | ||
| 120 | |||
| 121 | ZIG_EXTERN_C void ZigLLVMReplaceDebugArrays(struct ZigLLVMDIBuilder *dibuilder, struct ZigLLVMDIType *type, | ||
| 122 | struct ZigLLVMDIType **types_array, int types_array_len); | ||
| 123 | |||
| 124 | ZIG_EXTERN_C struct ZigLLVMDIType *ZigLLVMCreateSubroutineType(struct ZigLLVMDIBuilder *dibuilder_wrapped, | ||
| 125 | struct ZigLLVMDIType **types_array, int types_array_len, unsigned flags); | ||
| 126 | |||
| 127 | ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_unsigned(void); | ||
| 128 | ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_signed(void); | ||
| 129 | ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_float(void); | ||
| 130 | ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_boolean(void); | ||
| 131 | ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_unsigned_char(void); | ||
| 132 | ZIG_EXTERN_C unsigned ZigLLVMEncoding_DW_ATE_signed_char(void); | ||
| 133 | ZIG_EXTERN_C unsigned ZigLLVMLang_DW_LANG_C99(void); | ||
| 134 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_variable(void); | ||
| 135 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_structure_type(void); | ||
| 136 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void); | ||
| 137 | |||
| 138 | ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); | ||
| 139 | ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); | ||
| 140 | ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module); | ||
| 141 | |||
| 142 | ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column, | ||
| 143 | struct ZigLLVMDIScope *scope); | ||
| 144 | ZIG_EXTERN_C void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder); | ||
| 145 | |||
| 146 | ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMLexicalBlockToScope(struct ZigLLVMDILexicalBlock *lexical_block); | ||
| 147 | ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMCompileUnitToScope(struct ZigLLVMDICompileUnit *compile_unit); | ||
| 148 | ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMFileToScope(struct ZigLLVMDIFile *difile); | ||
| 149 | ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMSubprogramToScope(struct ZigLLVMDISubprogram *subprogram); | ||
| 150 | ZIG_EXTERN_C struct ZigLLVMDIScope *ZigLLVMTypeToScope(struct ZigLLVMDIType *type); | ||
| 151 | |||
| 152 | ZIG_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 | |||
| 156 | ZIG_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 | |||
| 160 | ZIG_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 | |||
| 164 | ZIG_EXTERN_C struct ZigLLVMDILexicalBlock *ZigLLVMCreateLexicalBlock(struct ZigLLVMDIBuilder *dbuilder, | ||
| 165 | struct ZigLLVMDIScope *scope, struct ZigLLVMDIFile *file, unsigned line, unsigned col); | ||
| 166 | |||
| 167 | ZIG_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 | |||
| 172 | ZIG_EXTERN_C struct ZigLLVMDIFile *ZigLLVMCreateFile(struct ZigLLVMDIBuilder *dibuilder, const char *filename, | ||
| 173 | const char *directory); | ||
| 174 | |||
| 175 | ZIG_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 | |||
| 180 | ZIG_EXTERN_C void ZigLLVMFnSetSubprogram(LLVMValueRef fn, struct ZigLLVMDISubprogram *subprogram); | ||
| 181 | |||
| 182 | ZIG_EXTERN_C void ZigLLVMDIBuilderFinalize(struct ZigLLVMDIBuilder *dibuilder); | ||
| 183 | |||
| 184 | ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclareAtEnd(struct ZigLLVMDIBuilder *dibuilder, LLVMValueRef storage, | ||
| 185 | struct ZigLLVMDILocalVariable *var_info, struct ZigLLVMDILocation *debug_loc, | ||
| 186 | LLVMBasicBlockRef basic_block_ref); | ||
| 187 | |||
| 188 | ZIG_EXTERN_C LLVMValueRef ZigLLVMInsertDeclare(struct ZigLLVMDIBuilder *dibuilder, LLVMValueRef storage, | ||
| 189 | struct ZigLLVMDILocalVariable *var_info, struct ZigLLVMDILocation *debug_loc, LLVMValueRef insert_before_instr); | ||
| 190 | ZIG_EXTERN_C struct ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, struct ZigLLVMDIScope *scope); | ||
| 191 | |||
| 192 | ZIG_EXTERN_C void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state); | ||
| 193 | |||
| 194 | ZIG_EXTERN_C void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value); | ||
| 195 | ZIG_EXTERN_C void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn); | ||
| 196 | |||
| 197 | ZIG_EXTERN_C void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv); | ||
| 198 | |||
| 199 | |||
| 200 | // copied from include/llvm/ADT/Triple.h | ||
| 201 | |||
| 202 | enum 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 | |||
| 259 | enum 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 | |||
| 288 | enum 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 | |||
| 310 | enum 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 | |||
| 348 | enum 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 | |||
| 376 | enum ZigLLVM_ObjectFormatType { | ||
| 377 | ZigLLVM_UnknownObjectFormat, | ||
| 378 | |||
| 379 | ZigLLVM_COFF, | ||
| 380 | ZigLLVM_ELF, | ||
| 381 | ZigLLVM_MachO, | ||
| 382 | ZigLLVM_Wasm, | ||
| 383 | }; | ||
| 384 | |||
| 385 | ZIG_EXTERN_C const char *ZigLLVMGetArchTypeName(enum ZigLLVM_ArchType arch); | ||
| 386 | ZIG_EXTERN_C const char *ZigLLVMGetSubArchTypeName(enum ZigLLVM_SubArchType sub_arch); | ||
| 387 | ZIG_EXTERN_C const char *ZigLLVMGetVendorTypeName(enum ZigLLVM_VendorType vendor); | ||
| 388 | ZIG_EXTERN_C const char *ZigLLVMGetOSTypeName(enum ZigLLVM_OSType os); | ||
| 389 | ZIG_EXTERN_C const char *ZigLLVMGetEnvironmentTypeName(enum ZigLLVM_EnvironmentType env_type); | ||
| 390 | |||
| 391 | ZIG_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 | |||
| 394 | ZIG_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 | |||
| 17 | struct ZigLLVMDIType; | ||
| 18 | struct ZigLLVMDIBuilder; | ||
| 19 | struct ZigLLVMDICompileUnit; | ||
| 20 | struct ZigLLVMDIScope; | ||
| 21 | struct ZigLLVMDIFile; | ||
| 22 | struct ZigLLVMDILexicalBlock; | ||
| 23 | struct ZigLLVMDISubprogram; | ||
| 24 | struct ZigLLVMDISubroutineType; | ||
| 25 | struct ZigLLVMDILocalVariable; | ||
| 26 | struct ZigLLVMDIGlobalVariable; | ||
| 27 | struct ZigLLVMDILocation; | ||
| 28 | struct ZigLLVMDIEnumerator; | ||
| 29 | struct ZigLLVMInsertionPoint; | ||
| 30 | |||
| 31 | void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R); | ||
| 32 | void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R); | ||
| 33 | |||
| 34 | char *ZigLLVMGetHostCPUName(void); | ||
| 35 | char *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. | ||
| 39 | enum ZigLLVM_EmitOutputType { | ||
| 40 | ZigLLVM_EmitAssembly, | ||
| 41 | ZigLLVM_EmitBinary, | ||
| 42 | ZigLLVM_EmitLLVMIr, | ||
| 43 | }; | ||
| 44 | |||
| 45 | bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, | ||
| 46 | const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug); | ||
| 47 | |||
| 48 | enum ZigLLVM_FnInline { | ||
| 49 | ZigLLVM_FnInlineAuto, | ||
| 50 | ZigLLVM_FnInlineAlways, | ||
| 51 | ZigLLVM_FnInlineNever, | ||
| 52 | }; | ||
| 53 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, | ||
| 54 | unsigned NumArgs, unsigned CC, ZigLLVM_FnInline fn_inline, const char *Name); | ||
| 55 | |||
| 56 | LLVMValueRef ZigLLVMBuildCmpXchg(LLVMBuilderRef builder, LLVMValueRef ptr, LLVMValueRef cmp, | ||
| 57 | LLVMValueRef new_val, LLVMAtomicOrdering success_ordering, | ||
| 58 | LLVMAtomicOrdering failure_ordering); | ||
| 59 | |||
| 60 | LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, | ||
| 61 | const char *name); | ||
| 62 | LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, | ||
| 63 | const char *name); | ||
| 64 | LLVMValueRef ZigLLVMBuildLShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, | ||
| 65 | const char *name); | ||
| 66 | LLVMValueRef ZigLLVMBuildAShrExact(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS, | ||
| 67 | const char *name); | ||
| 68 | |||
| 69 | ZigLLVMDIType *ZigLLVMCreateDebugPointerType(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *pointee_type, | ||
| 70 | uint64_t size_in_bits, uint64_t align_in_bits, const char *name); | ||
| 71 | |||
| 72 | ZigLLVMDIType *ZigLLVMCreateDebugBasicType(ZigLLVMDIBuilder *dibuilder, const char *name, | ||
| 73 | uint64_t size_in_bits, unsigned encoding); | ||
| 74 | |||
| 75 | ZigLLVMDIType *ZigLLVMCreateDebugArrayType(ZigLLVMDIBuilder *dibuilder, | ||
| 76 | uint64_t size_in_bits, uint64_t align_in_bits, ZigLLVMDIType *elem_type, | ||
| 77 | int elem_count); | ||
| 78 | |||
| 79 | ZigLLVMDIEnumerator *ZigLLVMCreateDebugEnumerator(ZigLLVMDIBuilder *dibuilder, const char *name, int64_t val); | ||
| 80 | |||
| 81 | ZigLLVMDIType *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 | |||
| 86 | ZigLLVMDIType *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 | |||
| 92 | ZigLLVMDIType *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 | |||
| 97 | ZigLLVMDIType *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 | |||
| 101 | ZigLLVMDIType *ZigLLVMCreateReplaceableCompositeType(ZigLLVMDIBuilder *dibuilder, unsigned tag, | ||
| 102 | const char *name, ZigLLVMDIScope *scope, ZigLLVMDIFile *file, unsigned line); | ||
| 103 | |||
| 104 | ZigLLVMDIType *ZigLLVMCreateDebugForwardDeclType(ZigLLVMDIBuilder *dibuilder, unsigned tag, | ||
| 105 | const char *name, ZigLLVMDIScope *scope, ZigLLVMDIFile *file, unsigned line); | ||
| 106 | |||
| 107 | void ZigLLVMReplaceTemporary(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *type, | ||
| 108 | ZigLLVMDIType *replacement); | ||
| 109 | |||
| 110 | void ZigLLVMReplaceDebugArrays(ZigLLVMDIBuilder *dibuilder, ZigLLVMDIType *type, | ||
| 111 | ZigLLVMDIType **types_array, int types_array_len); | ||
| 112 | |||
| 113 | ZigLLVMDIType *ZigLLVMCreateSubroutineType(ZigLLVMDIBuilder *dibuilder_wrapped, | ||
| 114 | ZigLLVMDIType **types_array, int types_array_len, unsigned flags); | ||
| 115 | |||
| 116 | unsigned ZigLLVMEncoding_DW_ATE_unsigned(void); | ||
| 117 | unsigned ZigLLVMEncoding_DW_ATE_signed(void); | ||
| 118 | unsigned ZigLLVMEncoding_DW_ATE_float(void); | ||
| 119 | unsigned ZigLLVMEncoding_DW_ATE_boolean(void); | ||
| 120 | unsigned ZigLLVMEncoding_DW_ATE_unsigned_char(void); | ||
| 121 | unsigned ZigLLVMEncoding_DW_ATE_signed_char(void); | ||
| 122 | unsigned ZigLLVMLang_DW_LANG_C99(void); | ||
| 123 | unsigned ZigLLVMTag_DW_variable(void); | ||
| 124 | unsigned ZigLLVMTag_DW_structure_type(void); | ||
| 125 | unsigned ZigLLVMTag_DW_union_type(void); | ||
| 126 | |||
| 127 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); | ||
| 128 | void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); | ||
| 129 | void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module); | ||
| 130 | |||
| 131 | void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column, ZigLLVMDIScope *scope); | ||
| 132 | void ZigLLVMClearCurrentDebugLocation(LLVMBuilderRef builder); | ||
| 133 | |||
| 134 | ZigLLVMDIScope *ZigLLVMLexicalBlockToScope(ZigLLVMDILexicalBlock *lexical_block); | ||
| 135 | ZigLLVMDIScope *ZigLLVMCompileUnitToScope(ZigLLVMDICompileUnit *compile_unit); | ||
| 136 | ZigLLVMDIScope *ZigLLVMFileToScope(ZigLLVMDIFile *difile); | ||
| 137 | ZigLLVMDIScope *ZigLLVMSubprogramToScope(ZigLLVMDISubprogram *subprogram); | ||
| 138 | ZigLLVMDIScope *ZigLLVMTypeToScope(ZigLLVMDIType *type); | ||
| 139 | |||
| 140 | ZigLLVMDILocalVariable *ZigLLVMCreateAutoVariable(ZigLLVMDIBuilder *dbuilder, | ||
| 141 | ZigLLVMDIScope *scope, const char *name, ZigLLVMDIFile *file, unsigned line_no, | ||
| 142 | ZigLLVMDIType *type, bool always_preserve, unsigned flags); | ||
| 143 | |||
| 144 | ZigLLVMDIGlobalVariable *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 | |||
| 148 | ZigLLVMDILocalVariable *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 | |||
| 152 | ZigLLVMDILexicalBlock *ZigLLVMCreateLexicalBlock(ZigLLVMDIBuilder *dbuilder, ZigLLVMDIScope *scope, | ||
| 153 | ZigLLVMDIFile *file, unsigned line, unsigned col); | ||
| 154 | |||
| 155 | ZigLLVMDICompileUnit *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 | |||
| 160 | ZigLLVMDIFile *ZigLLVMCreateFile(ZigLLVMDIBuilder *dibuilder, const char *filename, const char *directory); | ||
| 161 | |||
| 162 | ZigLLVMDISubprogram *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 | |||
| 167 | void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram); | ||
| 168 | |||
| 169 | void ZigLLVMDIBuilderFinalize(ZigLLVMDIBuilder *dibuilder); | ||
| 170 | |||
| 171 | LLVMValueRef ZigLLVMInsertDeclareAtEnd(ZigLLVMDIBuilder *dibuilder, LLVMValueRef storage, | ||
| 172 | ZigLLVMDILocalVariable *var_info, ZigLLVMDILocation *debug_loc, LLVMBasicBlockRef basic_block_ref); | ||
| 173 | LLVMValueRef ZigLLVMInsertDeclare(ZigLLVMDIBuilder *dibuilder, LLVMValueRef storage, | ||
| 174 | ZigLLVMDILocalVariable *var_info, ZigLLVMDILocation *debug_loc, LLVMValueRef insert_before_instr); | ||
| 175 | ZigLLVMDILocation *ZigLLVMGetDebugLoc(unsigned line, unsigned col, ZigLLVMDIScope *scope); | ||
| 176 | |||
| 177 | void ZigLLVMSetFastMath(LLVMBuilderRef builder_wrapped, bool on_state); | ||
| 178 | |||
| 179 | void ZigLLVMAddFunctionAttr(LLVMValueRef fn, const char *attr_name, const char *attr_value); | ||
| 180 | void ZigLLVMAddFunctionAttrCold(LLVMValueRef fn); | ||
| 181 | |||
| 182 | void ZigLLVMParseCommandLineOptions(int argc, const char *const *argv); | ||
| 183 | |||
| 184 | |||
| 185 | // copied from include/llvm/ADT/Triple.h | ||
| 186 | |||
| 187 | enum 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 | |||
| 244 | enum 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 | |||
| 273 | enum 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 | |||
| 295 | enum 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 | |||
| 333 | enum 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 | |||
| 361 | enum ZigLLVM_ObjectFormatType { | ||
| 362 | ZigLLVM_UnknownObjectFormat, | ||
| 363 | |||
| 364 | ZigLLVM_COFF, | ||
| 365 | ZigLLVM_ELF, | ||
| 366 | ZigLLVM_MachO, | ||
| 367 | ZigLLVM_Wasm, | ||
| 368 | }; | ||
| 369 | |||
| 370 | const char *ZigLLVMGetArchTypeName(ZigLLVM_ArchType arch); | ||
| 371 | const char *ZigLLVMGetSubArchTypeName(ZigLLVM_SubArchType sub_arch); | ||
| 372 | const char *ZigLLVMGetVendorTypeName(ZigLLVM_VendorType vendor); | ||
| 373 | const char *ZigLLVMGetOSTypeName(ZigLLVM_OSType os); | ||
| 374 | const 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 | */ | ||
| 379 | struct Buf; | ||
| 380 | |||
| 381 | bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_count, Buf *diag); | ||
| 382 | |||
| 383 | void 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 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const debug = std.debug; | ||
| 2 | const assert = debug.assert; | 3 | const assert = debug.assert; |
| 3 | const mem = @import("mem.zig"); | 4 | const mem = std.mem; |
| 4 | const Allocator = mem.Allocator; | 5 | const Allocator = mem.Allocator; |
| 5 | 6 | ||
| 6 | pub fn ArrayList(comptime T: type) -> type { | 7 | pub fn ArrayList(comptime T: type) -> type { |
std/base64.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const assert = @import("debug.zig").assert; | 1 | const std = @import("index.zig"); |
| 2 | const mem = @import("mem.zig"); | 2 | const assert = std.debug.assert; |
| 3 | const mem = std.mem; | ||
| 3 | 4 | ||
| 4 | pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | 5 | pub const standard_alphabet_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| 5 | pub const standard_pad_char = '='; | 6 | pub const standard_pad_char = '='; |
std/buffer.zig+5-4| ... | @@ -1,10 +1,11 @@ | ... | @@ -1,10 +1,11 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const mem = @import("mem.zig"); | 2 | const debug = std.debug; |
| 3 | const mem = std.mem; | ||
| 3 | const Allocator = mem.Allocator; | 4 | const Allocator = mem.Allocator; |
| 4 | const assert = debug.assert; | 5 | const assert = debug.assert; |
| 5 | const ArrayList = @import("array_list.zig").ArrayList; | 6 | const ArrayList = std.ArrayList; |
| 6 | 7 | ||
| 7 | const fmt = @import("fmt/index.zig"); | 8 | const fmt = std.fmt; |
| 8 | 9 | ||
| 9 | /// A buffer that allocates memory and maintains a null byte at the end. | 10 | /// A buffer that allocates memory and maintains a null byte at the end. |
| 10 | pub const Buffer = struct { | 11 | pub const Buffer = struct { |
std/build.zig+7| ... | @@ -784,6 +784,13 @@ const Target = union(enum) { | ... | @@ -784,6 +784,13 @@ const Target = union(enum) { |
| 784 | }; | 784 | }; |
| 785 | } | 785 | } |
| 786 | 786 | ||
| 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 | |||
| 787 | pub fn getOs(self: &const Target) -> builtin.Os { | 794 | pub fn getOs(self: &const Target) -> builtin.Os { |
| 788 | return switch (*self) { | 795 | return switch (*self) { |
| 789 | Target.Native => builtin.os, | 796 | Target.Native => builtin.os, |
std/cstr.zig+57-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const mem = @import("mem.zig"); | 2 | const debug = std.debug; |
| 3 | const mem = std.mem; | ||
| 3 | const assert = debug.assert; | 4 | const assert = debug.assert; |
| 4 | 5 | ||
| 5 | pub fn len(ptr: &const u8) -> usize { | 6 | pub fn len(ptr: &const u8) -> usize { |
| ... | @@ -47,3 +48,57 @@ pub fn addNullByte(allocator: &mem.Allocator, slice: []const u8) -> %[]u8 { | ... | @@ -47,3 +48,57 @@ pub fn addNullByte(allocator: &mem.Allocator, slice: []const u8) -> %[]u8 { |
| 47 | result[slice.len] = 0; | 48 | result[slice.len] = 0; |
| 48 | return result; | 49 | return result; |
| 49 | } | 50 | } |
| 51 | |||
| 52 | pub 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 @@ | ||
| 1 | const std = @import("index.zig"); | ||
| 2 | const math = std.math; | ||
| 3 | const mem = std.mem; | ||
| 4 | const io = std.io; | ||
| 5 | const os = std.os; | ||
| 6 | const elf = @import("elf.zig"); | ||
| 7 | const DW = @import("dwarf.zig"); | ||
| 8 | const ArrayList = std.ArrayList; | ||
| 9 | const builtin = @import("builtin"); | ||
| 10 | |||
| 11 | error MissingDebugInfo; | ||
| 12 | error InvalidDebugInfo; | ||
| 13 | error 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 | ||
| 19 | var stderr_file: io.File = undefined; | ||
| 20 | var stderr_file_out_stream: io.FileOutStream = undefined; | ||
| 21 | var stderr_stream: ?&io.OutStream = null; | ||
| 22 | pub fn warn(comptime fmt: []const u8, args: ...) { | ||
| 23 | const stderr = getStderrStream() %% return; | ||
| 24 | stderr.print(fmt, args) %% return; | ||
| 25 | } | ||
| 26 | fn 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. | ||
| 39 | pub 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. | ||
| 49 | pub 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. | ||
| 64 | pub fn assertOrPanic(ok: bool) { | ||
| 65 | if (!ok) { | ||
| 66 | @panic("assertion failure"); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | var panicking = false; | ||
| 71 | /// This is the default panic implementation. | ||
| 72 | pub 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 | |||
| 94 | const GREEN = "\x1b[32;1m"; | ||
| 95 | const WHITE = "\x1b[37;1m"; | ||
| 96 | const DIM = "\x1b[2m"; | ||
| 97 | const RESET = "\x1b[0m"; | ||
| 98 | |||
| 99 | error PathNotFound; | ||
| 100 | error InvalidDebugInfo; | ||
| 101 | |||
| 102 | pub 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 | |||
| 196 | fn 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 | |||
| 229 | const 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 | |||
| 251 | const PcRange = struct { | ||
| 252 | start: u64, | ||
| 253 | end: u64, | ||
| 254 | }; | ||
| 255 | |||
| 256 | const CompileUnit = struct { | ||
| 257 | version: u16, | ||
| 258 | is_64: bool, | ||
| 259 | die: &Die, | ||
| 260 | index: usize, | ||
| 261 | pc_range: ?PcRange, | ||
| 262 | }; | ||
| 263 | |||
| 264 | const AbbrevTable = ArrayList(AbbrevTableEntry); | ||
| 265 | |||
| 266 | const AbbrevTableHeader = struct { | ||
| 267 | // offset from .debug_abbrev | ||
| 268 | offset: u64, | ||
| 269 | table: AbbrevTable, | ||
| 270 | }; | ||
| 271 | |||
| 272 | const AbbrevTableEntry = struct { | ||
| 273 | has_children: bool, | ||
| 274 | abbrev_code: u64, | ||
| 275 | tag_id: u64, | ||
| 276 | attrs: ArrayList(AbbrevAttr), | ||
| 277 | }; | ||
| 278 | |||
| 279 | const AbbrevAttr = struct { | ||
| 280 | attr_id: u64, | ||
| 281 | form_id: u64, | ||
| 282 | }; | ||
| 283 | |||
| 284 | const 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 | |||
| 298 | const 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 | |||
| 311 | const 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 | |||
| 364 | const FileEntry = struct { | ||
| 365 | file_name: []const u8, | ||
| 366 | dir_index: usize, | ||
| 367 | mtime: usize, | ||
| 368 | len_bytes: usize, | ||
| 369 | }; | ||
| 370 | |||
| 371 | const 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 | |||
| 382 | const 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 | |||
| 459 | fn 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 | |||
| 470 | fn 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 | |||
| 476 | fn 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 | |||
| 483 | fn 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 | |||
| 488 | fn 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 | |||
| 493 | fn 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 | |||
| 500 | fn 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 | |||
| 505 | fn 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 | |||
| 511 | fn 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 | |||
| 516 | fn 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 | |||
| 521 | fn 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 | |||
| 571 | fn 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. | ||
| 603 | fn 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 | |||
| 617 | fn 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 | |||
| 625 | fn 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 | |||
| 647 | fn 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 | |||
| 825 | fn 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 | |||
| 901 | fn 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 | |||
| 937 | fn 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 | |||
| 948 | fn 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 | |||
| 969 | fn 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 | |||
| 992 | pub const global_allocator = &global_fixed_allocator.allocator; | ||
| 993 | var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]); | ||
| 994 | var 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. | ||
| 998 | pub 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 @@ | ||
| 1 | const std = @import("../index.zig"); | ||
| 2 | const mem = std.mem; | ||
| 3 | |||
| 4 | /// Allocator that fails after N allocations, useful for making sure out of | ||
| 5 | /// memory conditions are handled correctly. | ||
| 6 | pub 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 @@ | ||
| 1 | const std = @import("../index.zig"); | ||
| 2 | const math = std.math; | ||
| 3 | const mem = std.mem; | ||
| 4 | const io = std.io; | ||
| 5 | const os = std.os; | ||
| 6 | const elf = std.elf; | ||
| 7 | const DW = std.dwarf; | ||
| 8 | const ArrayList = std.ArrayList; | ||
| 9 | const builtin = @import("builtin"); | ||
| 10 | |||
| 11 | pub const FailingAllocator = @import("failing_allocator.zig").FailingAllocator; | ||
| 12 | |||
| 13 | error MissingDebugInfo; | ||
| 14 | error InvalidDebugInfo; | ||
| 15 | error 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 | ||
| 21 | var stderr_file: io.File = undefined; | ||
| 22 | var stderr_file_out_stream: io.FileOutStream = undefined; | ||
| 23 | var stderr_stream: ?&io.OutStream = null; | ||
| 24 | pub fn warn(comptime fmt: []const u8, args: ...) { | ||
| 25 | const stderr = getStderrStream() %% return; | ||
| 26 | stderr.print(fmt, args) %% return; | ||
| 27 | } | ||
| 28 | fn 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. | ||
| 41 | pub 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. | ||
| 51 | pub 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. | ||
| 66 | pub fn assertOrPanic(ok: bool) { | ||
| 67 | if (!ok) { | ||
| 68 | @panic("assertion failure"); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | var panicking = false; | ||
| 73 | /// This is the default panic implementation. | ||
| 74 | pub 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 | |||
| 96 | const GREEN = "\x1b[32;1m"; | ||
| 97 | const WHITE = "\x1b[37;1m"; | ||
| 98 | const DIM = "\x1b[2m"; | ||
| 99 | const RESET = "\x1b[0m"; | ||
| 100 | |||
| 101 | error PathNotFound; | ||
| 102 | error InvalidDebugInfo; | ||
| 103 | |||
| 104 | pub 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 | |||
| 198 | fn 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 | |||
| 231 | const 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 | |||
| 253 | const PcRange = struct { | ||
| 254 | start: u64, | ||
| 255 | end: u64, | ||
| 256 | }; | ||
| 257 | |||
| 258 | const CompileUnit = struct { | ||
| 259 | version: u16, | ||
| 260 | is_64: bool, | ||
| 261 | die: &Die, | ||
| 262 | index: usize, | ||
| 263 | pc_range: ?PcRange, | ||
| 264 | }; | ||
| 265 | |||
| 266 | const AbbrevTable = ArrayList(AbbrevTableEntry); | ||
| 267 | |||
| 268 | const AbbrevTableHeader = struct { | ||
| 269 | // offset from .debug_abbrev | ||
| 270 | offset: u64, | ||
| 271 | table: AbbrevTable, | ||
| 272 | }; | ||
| 273 | |||
| 274 | const AbbrevTableEntry = struct { | ||
| 275 | has_children: bool, | ||
| 276 | abbrev_code: u64, | ||
| 277 | tag_id: u64, | ||
| 278 | attrs: ArrayList(AbbrevAttr), | ||
| 279 | }; | ||
| 280 | |||
| 281 | const AbbrevAttr = struct { | ||
| 282 | attr_id: u64, | ||
| 283 | form_id: u64, | ||
| 284 | }; | ||
| 285 | |||
| 286 | const 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 | |||
| 300 | const 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 | |||
| 313 | const 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 | |||
| 366 | const FileEntry = struct { | ||
| 367 | file_name: []const u8, | ||
| 368 | dir_index: usize, | ||
| 369 | mtime: usize, | ||
| 370 | len_bytes: usize, | ||
| 371 | }; | ||
| 372 | |||
| 373 | const 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 | |||
| 384 | const 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 | |||
| 461 | fn 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 | |||
| 472 | fn 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 | |||
| 478 | fn 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 | |||
| 485 | fn 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 | |||
| 490 | fn 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 | |||
| 495 | fn 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 | |||
| 502 | fn 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 | |||
| 507 | fn 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 | |||
| 513 | fn 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 | |||
| 518 | fn 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 | |||
| 523 | fn 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 | |||
| 573 | fn 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. | ||
| 605 | fn 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 | |||
| 619 | fn 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 | |||
| 627 | fn 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 | |||
| 649 | fn 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 | |||
| 827 | fn 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 | |||
| 903 | fn 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 | |||
| 939 | fn 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 | |||
| 950 | fn 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 | |||
| 971 | fn 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 | |||
| 994 | pub const global_allocator = &global_fixed_allocator.allocator; | ||
| 995 | var global_fixed_allocator = mem.FixedBufferAllocator.init(global_allocator_mem[0..]); | ||
| 996 | var global_allocator_mem: [100 * 1024]u8 = undefined; | ||
std/fmt/errol/index.zig+4-3| ... | @@ -1,10 +1,11 @@ | ... | @@ -1,10 +1,11 @@ |
| 1 | const std = @import("../../index.zig"); | ||
| 1 | const enum3 = @import("enum3.zig").enum3; | 2 | const enum3 = @import("enum3.zig").enum3; |
| 2 | const enum3_data = @import("enum3.zig").enum3_data; | 3 | const enum3_data = @import("enum3.zig").enum3_data; |
| 3 | const lookup_table = @import("lookup.zig").lookup_table; | 4 | const lookup_table = @import("lookup.zig").lookup_table; |
| 4 | const HP = @import("lookup.zig").HP; | 5 | const HP = @import("lookup.zig").HP; |
| 5 | const math = @import("../../math/index.zig"); | 6 | const math = std.math; |
| 6 | const mem = @import("../../mem.zig"); | 7 | const mem = std.mem; |
| 7 | const assert = @import("../../debug.zig").assert; | 8 | const assert = std.debug.assert; |
| 8 | 9 | ||
| 9 | pub const FloatDecimal = struct { | 10 | pub const FloatDecimal = struct { |
| 10 | digits: []u8, | 11 | digits: []u8, |
std/fmt/index.zig+4-3| ... | @@ -1,7 +1,8 @@ | ... | @@ -1,7 +1,8 @@ |
| 1 | const math = @import("../math/index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const debug = @import("../debug.zig"); | 2 | const math = std.math; |
| 3 | const debug = std.debug; | ||
| 3 | const assert = debug.assert; | 4 | const assert = debug.assert; |
| 4 | const mem = @import("../mem.zig"); | 5 | const mem = std.mem; |
| 5 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 6 | const errol3 = @import("errol/index.zig").errol3; | 7 | const errol3 = @import("errol/index.zig").errol3; |
| 7 | 8 |
std/hash_map.zig+4-3| ... | @@ -1,7 +1,8 @@ | ... | @@ -1,7 +1,8 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const debug = std.debug; | ||
| 2 | const assert = debug.assert; | 3 | const assert = debug.assert; |
| 3 | const math = @import("math/index.zig"); | 4 | const math = std.math; |
| 4 | const mem = @import("mem.zig"); | 5 | const mem = std.mem; |
| 5 | const Allocator = mem.Allocator; | 6 | const Allocator = mem.Allocator; |
| 6 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 7 | 8 |
std/heap.zig+5-4| ... | @@ -1,10 +1,11 @@ | ... | @@ -1,10 +1,11 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const debug = std.debug; | ||
| 2 | const assert = debug.assert; | 3 | const assert = debug.assert; |
| 3 | const mem = @import("mem.zig"); | 4 | const mem = std.mem; |
| 4 | const os = @import("os/index.zig"); | 5 | const os = std.os; |
| 5 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 6 | const Os = builtin.Os; | 7 | const Os = builtin.Os; |
| 7 | const c = @import("c/index.zig"); | 8 | const c = std.c; |
| 8 | 9 | ||
| 9 | const Allocator = mem.Allocator; | 10 | const Allocator = mem.Allocator; |
| 10 | 11 |
std/index.zig+2-2| ... | @@ -11,7 +11,7 @@ pub const base64 = @import("base64.zig"); | ... | @@ -11,7 +11,7 @@ pub const base64 = @import("base64.zig"); |
| 11 | pub const build = @import("build.zig"); | 11 | pub const build = @import("build.zig"); |
| 12 | pub const c = @import("c/index.zig"); | 12 | pub const c = @import("c/index.zig"); |
| 13 | pub const cstr = @import("cstr.zig"); | 13 | pub const cstr = @import("cstr.zig"); |
| 14 | pub const debug = @import("debug.zig"); | 14 | pub const debug = @import("debug/index.zig"); |
| 15 | pub const dwarf = @import("dwarf.zig"); | 15 | pub const dwarf = @import("dwarf.zig"); |
| 16 | pub const elf = @import("elf.zig"); | 16 | pub const elf = @import("elf.zig"); |
| 17 | pub const empty_import = @import("empty.zig"); | 17 | pub const empty_import = @import("empty.zig"); |
| ... | @@ -39,7 +39,7 @@ test "std" { | ... | @@ -39,7 +39,7 @@ test "std" { |
| 39 | _ = @import("build.zig"); | 39 | _ = @import("build.zig"); |
| 40 | _ = @import("c/index.zig"); | 40 | _ = @import("c/index.zig"); |
| 41 | _ = @import("cstr.zig"); | 41 | _ = @import("cstr.zig"); |
| 42 | _ = @import("debug.zig"); | 42 | _ = @import("debug/index.zig"); |
| 43 | _ = @import("dwarf.zig"); | 43 | _ = @import("dwarf.zig"); |
| 44 | _ = @import("elf.zig"); | 44 | _ = @import("elf.zig"); |
| 45 | _ = @import("empty.zig"); | 45 | _ = @import("empty.zig"); |
std/linked_list.zig+3-2| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const debug = std.debug; | ||
| 2 | const assert = debug.assert; | 3 | const assert = debug.assert; |
| 3 | const mem = @import("mem.zig"); | 4 | const mem = std.mem; |
| 4 | const Allocator = mem.Allocator; | 5 | const Allocator = mem.Allocator; |
| 5 | 6 | ||
| 6 | /// Generic doubly linked list. | 7 | /// Generic doubly linked list. |
std/math/acos.zig+3-2| ... | @@ -2,8 +2,9 @@ | ... | @@ -2,8 +2,9 @@ |
| 2 | // | 2 | // |
| 3 | // - acos(x) = nan if x < -1 or x > 1 | 3 | // - acos(x) = nan if x < -1 or x > 1 |
| 4 | 4 | ||
| 5 | const math = @import("index.zig"); | 5 | const std = @import("../index.zig"); |
| 6 | const assert = @import("../debug.zig").assert; | 6 | const math = std.math; |
| 7 | const assert = std.debug.assert; | ||
| 7 | 8 | ||
| 8 | pub fn acos(x: var) -> @typeOf(x) { | 9 | pub fn acos(x: var) -> @typeOf(x) { |
| 9 | const T = @typeOf(x); | 10 | const T = @typeOf(x); |
std/math/acosh.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - acosh(nan) = nan | 4 | // - acosh(nan) = nan |
| 5 | 5 | ||
| 6 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn acosh(x: var) -> @typeOf(x) { | 11 | pub fn acosh(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/asin.zig+3-2| ... | @@ -3,8 +3,9 @@ | ... | @@ -3,8 +3,9 @@ |
| 3 | // - asin(+-0) = +-0 | 3 | // - asin(+-0) = +-0 |
| 4 | // - asin(x) = nan if x < -1 or x > 1 | 4 | // - asin(x) = nan if x < -1 or x > 1 |
| 5 | 5 | ||
| 6 | const math = @import("index.zig"); | 6 | const std = @import("../index.zig"); |
| 7 | const assert = @import("../debug.zig").assert; | 7 | const math = std.math; |
| 8 | const assert = std.debug.assert; | ||
| 8 | 9 | ||
| 9 | pub fn asin(x: var) -> @typeOf(x) { | 10 | pub fn asin(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
std/math/asinh.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - asinh(+-inf) = +-inf | 4 | // - asinh(+-inf) = +-inf |
| 5 | // - asinh(nan) = nan | 5 | // - asinh(nan) = nan |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn asinh(x: var) -> @typeOf(x) { | 11 | pub fn asinh(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/atan.zig+3-2| ... | @@ -3,8 +3,9 @@ | ... | @@ -3,8 +3,9 @@ |
| 3 | // - atan(+-0) = +-0 | 3 | // - atan(+-0) = +-0 |
| 4 | // - atan(+-inf) = +-pi/2 | 4 | // - atan(+-inf) = +-pi/2 |
| 5 | 5 | ||
| 6 | const math = @import("index.zig"); | 6 | const std = @import("../index.zig"); |
| 7 | const assert = @import("../debug.zig").assert; | 7 | const math = std.math; |
| 8 | const assert = std.debug.assert; | ||
| 8 | 9 | ||
| 9 | pub fn atan(x: var) -> @typeOf(x) { | 10 | pub fn atan(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
std/math/atan2.zig+3-2| ... | @@ -18,8 +18,9 @@ | ... | @@ -18,8 +18,9 @@ |
| 18 | // atan2(+inf, x) = +pi/2 | 18 | // atan2(+inf, x) = +pi/2 |
| 19 | // atan2(-inf, x) = -pi/2 | 19 | // atan2(-inf, x) = -pi/2 |
| 20 | 20 | ||
| 21 | const math = @import("index.zig"); | 21 | const std = @import("../index.zig"); |
| 22 | const assert = @import("../debug.zig").assert; | 22 | const math = std.math; |
| 23 | const assert = std.debug.assert; | ||
| 23 | 24 | ||
| 24 | fn atan2(comptime T: type, x: T, y: T) -> T { | 25 | fn atan2(comptime T: type, x: T, y: T) -> T { |
| 25 | return switch (T) { | 26 | return switch (T) { |
std/math/atanh.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - atanh(x) = nan if |x| > 1 with signal | 4 | // - atanh(x) = nan if |x| > 1 with signal |
| 5 | // - atanh(nan) = nan | 5 | // - atanh(nan) = nan |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn atanh(x: var) -> @typeOf(x) { | 11 | pub fn atanh(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/cbrt.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - cbrt(+-inf) = +-inf | 4 | // - cbrt(+-inf) = +-inf |
| 5 | // - cbrt(nan) = nan | 5 | // - cbrt(nan) = nan |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn cbrt(x: var) -> @typeOf(x) { | 11 | pub fn cbrt(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/ceil.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - ceil(nan) = nan | 5 | // - ceil(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | 11 | ||
| 11 | pub fn ceil(x: var) -> @typeOf(x) { | 12 | pub fn ceil(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
std/math/copysign.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn copysign(comptime T: type, x: T, y: T) -> T { | 5 | pub fn copysign(comptime T: type, x: T, y: T) -> T { |
| 5 | return switch (T) { | 6 | return switch (T) { |
std/math/cos.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - cos(nan) = nan | 4 | // - cos(nan) = nan |
| 5 | 5 | ||
| 6 | const builtin = @import("builtin"); | 6 | const builtin = @import("builtin"); |
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn cos(x: var) -> @typeOf(x) { | 11 | pub fn cos(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/cosh.zig+3-2| ... | @@ -5,9 +5,10 @@ | ... | @@ -5,9 +5,10 @@ |
| 5 | // - cosh(nan) = nan | 5 | // - cosh(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const math = std.math; | ||
| 9 | const expo2 = @import("expo2.zig").expo2; | 10 | const expo2 = @import("expo2.zig").expo2; |
| 10 | const assert = @import("../debug.zig").assert; | 11 | const assert = std.debug.assert; |
| 11 | 12 | ||
| 12 | pub fn cosh(x: var) -> @typeOf(x) { | 13 | pub fn cosh(x: var) -> @typeOf(x) { |
| 13 | const T = @typeOf(x); | 14 | const T = @typeOf(x); |
std/math/exp.zig+3-2| ... | @@ -3,8 +3,9 @@ | ... | @@ -3,8 +3,9 @@ |
| 3 | // - exp(+inf) = +inf | 3 | // - exp(+inf) = +inf |
| 4 | // - exp(nan) = nan | 4 | // - exp(nan) = nan |
| 5 | 5 | ||
| 6 | const math = @import("index.zig"); | 6 | const std = @import("../index.zig"); |
| 7 | const assert = @import("../debug.zig").assert; | 7 | const math = std.math; |
| 8 | const assert = std.debug.assert; | ||
| 8 | 9 | ||
| 9 | pub fn exp(x: var) -> @typeOf(x) { | 10 | pub fn exp(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
std/math/exp2.zig+3-2| ... | @@ -3,8 +3,9 @@ | ... | @@ -3,8 +3,9 @@ |
| 3 | // - exp2(+inf) = +inf | 3 | // - exp2(+inf) = +inf |
| 4 | // - exp2(nan) = nan | 4 | // - exp2(nan) = nan |
| 5 | 5 | ||
| 6 | const math = @import("index.zig"); | 6 | const std = @import("../index.zig"); |
| 7 | const assert = @import("../debug.zig").assert; | 7 | const math = std.math; |
| 8 | const assert = std.debug.assert; | ||
| 8 | 9 | ||
| 9 | pub fn exp2(x: var) -> @typeOf(x) { | 10 | pub fn exp2(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
std/math/expm1.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - expm1(-inf) = -1 | 4 | // - expm1(-inf) = -1 |
| 5 | // - expm1(nan) = nan | 5 | // - expm1(nan) = nan |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn expm1(x: var) -> @typeOf(x) { | 11 | pub fn expm1(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/fabs.zig+3-2| ... | @@ -3,8 +3,9 @@ | ... | @@ -3,8 +3,9 @@ |
| 3 | // - fabs(+-inf) = +inf | 3 | // - fabs(+-inf) = +inf |
| 4 | // - fabs(nan) = nan | 4 | // - fabs(nan) = nan |
| 5 | 5 | ||
| 6 | const math = @import("index.zig"); | 6 | const std = @import("../index.zig"); |
| 7 | const assert = @import("../debug.zig").assert; | 7 | const math = std.math; |
| 8 | const assert = std.debug.assert; | ||
| 8 | 9 | ||
| 9 | pub fn fabs(x: var) -> @typeOf(x) { | 10 | pub fn fabs(x: var) -> @typeOf(x) { |
| 10 | const T = @typeOf(x); | 11 | const T = @typeOf(x); |
std/math/floor.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - floor(nan) = nan | 5 | // - floor(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const assert = std.debug.assert; |
| 9 | const math = @import("index.zig"); | 9 | const std = @import("../index.zig"); |
| 10 | const math = std.math; | ||
| 10 | 11 | ||
| 11 | pub fn floor(x: var) -> @typeOf(x) { | 12 | pub fn floor(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
std/math/fma.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn fma(comptime T: type, x: T, y: T, z: T) -> T { | 5 | pub fn fma(comptime T: type, x: T, y: T, z: T) -> T { |
| 5 | return switch (T) { | 6 | return switch (T) { |
std/math/frexp.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - frexp(+-inf) = +-inf, 0 | 4 | // - frexp(+-inf) = +-inf, 0 |
| 5 | // - frexp(nan) = nan, undefined | 5 | // - frexp(nan) = nan, undefined |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | fn frexp_result(comptime T: type) -> type { | 11 | fn frexp_result(comptime T: type) -> type { |
| 11 | return struct { | 12 | return struct { |
std/math/hypot.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - hypot(nan, y) = nan | 5 | // - hypot(nan, y) = nan |
| 6 | // - hypot(x, nan) = nan | 6 | // - hypot(x, nan) = nan |
| 7 | 7 | ||
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | 11 | ||
| 11 | pub fn hypot(comptime T: type, x: T, y: T) -> T { | 12 | pub fn hypot(comptime T: type, x: T, y: T) -> T { |
| 12 | return switch (T) { | 13 | return switch (T) { |
std/math/ilogb.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - ilogb(0) = @maxValue(i32) | 4 | // - ilogb(0) = @maxValue(i32) |
| 5 | // - ilogb(nan) = @maxValue(i32) | 5 | // - ilogb(nan) = @maxValue(i32) |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn ilogb(x: var) -> i32 { | 11 | pub fn ilogb(x: var) -> i32 { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/math/index.zig+2-1| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const builtin = @import("builtin"); | 1 | const builtin = @import("builtin"); |
| 2 | const std = @import("../index.zig"); | ||
| 2 | const TypeId = builtin.TypeId; | 3 | const TypeId = builtin.TypeId; |
| 3 | const assert = @import("../debug.zig").assert; | 4 | const assert = std.debug.assert; |
| 4 | 5 | ||
| 5 | pub const e = 2.71828182845904523536028747135266249775724709369995; | 6 | pub const e = 2.71828182845904523536028747135266249775724709369995; |
| 6 | pub const pi = 3.14159265358979323846264338327950288419716939937510; | 7 | pub const pi = 3.14159265358979323846264338327950288419716939937510; |
std/math/inf.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn inf(comptime T: type) -> T { | 5 | pub fn inf(comptime T: type) -> T { |
| 5 | return switch (T) { | 6 | return switch (T) { |
std/math/isfinite.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn isFinite(x: var) -> bool { | 5 | pub fn isFinite(x: var) -> bool { |
| 5 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
std/math/isinf.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn isInf(x: var) -> bool { | 5 | pub fn isInf(x: var) -> bool { |
| 5 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
std/math/isnan.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn isNan(x: var) -> bool { | 5 | pub fn isNan(x: var) -> bool { |
| 5 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
std/math/isnormal.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn isNormal(x: var) -> bool { | 5 | pub fn isNormal(x: var) -> bool { |
| 5 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
std/math/ln.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - ln(x) = nan if x < 0 | 5 | // - ln(x) = nan if x < 0 |
| 6 | // - ln(nan) = nan | 6 | // - ln(nan) = nan |
| 7 | 7 | ||
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | const builtin = @import("builtin"); | 11 | const builtin = @import("builtin"); |
| 11 | const TypeId = builtin.TypeId; | 12 | const TypeId = builtin.TypeId; |
| 12 | 13 |
std/math/log.zig+3-2| ... | @@ -1,7 +1,8 @@ | ... | @@ -1,7 +1,8 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const math = std.math; | ||
| 2 | const builtin = @import("builtin"); | 3 | const builtin = @import("builtin"); |
| 3 | const TypeId = builtin.TypeId; | 4 | const TypeId = builtin.TypeId; |
| 4 | const assert = @import("../debug.zig").assert; | 5 | const assert = std.debug.assert; |
| 5 | 6 | ||
| 6 | pub fn log(comptime T: type, base: T, x: T) -> T { | 7 | pub fn log(comptime T: type, base: T, x: T) -> T { |
| 7 | if (base == 2) { | 8 | if (base == 2) { |
std/math/log10.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - log10(x) = nan if x < 0 | 5 | // - log10(x) = nan if x < 0 |
| 6 | // - log10(nan) = nan | 6 | // - log10(nan) = nan |
| 7 | 7 | ||
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | const builtin = @import("builtin"); | 11 | const builtin = @import("builtin"); |
| 11 | const TypeId = builtin.TypeId; | 12 | const TypeId = builtin.TypeId; |
| 12 | 13 |
std/math/log1p.zig+3-2| ... | @@ -6,8 +6,9 @@ | ... | @@ -6,8 +6,9 @@ |
| 6 | // - log1p(x) = nan if x < -1 | 6 | // - log1p(x) = nan if x < -1 |
| 7 | // - log1p(nan) = nan | 7 | // - log1p(nan) = nan |
| 8 | 8 | ||
| 9 | const math = @import("index.zig"); | 9 | const std = @import("../index.zig"); |
| 10 | const assert = @import("../debug.zig").assert; | 10 | const math = std.math; |
| 11 | const assert = std.debug.assert; | ||
| 11 | 12 | ||
| 12 | pub fn log1p(x: var) -> @typeOf(x) { | 13 | pub fn log1p(x: var) -> @typeOf(x) { |
| 13 | const T = @typeOf(x); | 14 | const T = @typeOf(x); |
std/math/log2.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - log2(x) = nan if x < 0 | 5 | // - log2(x) = nan if x < 0 |
| 6 | // - log2(nan) = nan | 6 | // - log2(nan) = nan |
| 7 | 7 | ||
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | const builtin = @import("builtin"); | 11 | const builtin = @import("builtin"); |
| 11 | const TypeId = builtin.TypeId; | 12 | const TypeId = builtin.TypeId; |
| 12 | 13 |
std/math/modf.zig+3-2| ... | @@ -3,8 +3,9 @@ | ... | @@ -3,8 +3,9 @@ |
| 3 | // - modf(+-inf) = +-inf, nan | 3 | // - modf(+-inf) = +-inf, nan |
| 4 | // - modf(nan) = nan, nan | 4 | // - modf(nan) = nan, nan |
| 5 | 5 | ||
| 6 | const math = @import("index.zig"); | 6 | const std = @import("../index.zig"); |
| 7 | const assert = @import("../debug.zig").assert; | 7 | const math = std.math; |
| 8 | const assert = std.debug.assert; | ||
| 8 | 9 | ||
| 9 | fn modf_result(comptime T: type) -> type { | 10 | fn modf_result(comptime T: type) -> type { |
| 10 | return struct { | 11 | return struct { |
std/math/pow.zig+3-2| ... | @@ -22,8 +22,9 @@ | ... | @@ -22,8 +22,9 @@ |
| 22 | // pow(x, y) = nan for finite x < 0 and finite non-integer y | 22 | // pow(x, y) = nan for finite x < 0 and finite non-integer y |
| 23 | 23 | ||
| 24 | const builtin = @import("builtin"); | 24 | const builtin = @import("builtin"); |
| 25 | const math = @import("index.zig"); | 25 | const std = @import("../index.zig"); |
| 26 | const assert = @import("../debug.zig").assert; | 26 | const math = std.math; |
| 27 | const assert = std.debug.assert; | ||
| 27 | 28 | ||
| 28 | // This implementation is taken from the go stlib, musl is a bit more complex. | 29 | // This implementation is taken from the go stlib, musl is a bit more complex. |
| 29 | pub fn pow(comptime T: type, x: T, y: T) -> T { | 30 | pub fn pow(comptime T: type, x: T, y: T) -> T { |
std/math/round.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - round(nan) = nan | 5 | // - round(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const assert = std.debug.assert; |
| 9 | const math = @import("index.zig"); | 9 | const std = @import("../index.zig"); |
| 10 | const math = std.math; | ||
| 10 | 11 | ||
| 11 | pub fn round(x: var) -> @typeOf(x) { | 12 | pub fn round(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
std/math/scalbn.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn scalbn(x: var, n: i32) -> @typeOf(x) { | 5 | pub fn scalbn(x: var, n: i32) -> @typeOf(x) { |
| 5 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
std/math/signbit.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const math = @import("index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const math = std.math; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub fn signbit(x: var) -> bool { | 5 | pub fn signbit(x: var) -> bool { |
| 5 | const T = @typeOf(x); | 6 | const T = @typeOf(x); |
std/math/sin.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - sin(nan) = nan | 5 | // - sin(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | 11 | ||
| 11 | pub fn sin(x: var) -> @typeOf(x) { | 12 | pub fn sin(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
std/math/sinh.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - sinh(nan) = nan | 5 | // - sinh(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | const expo2 = @import("expo2.zig").expo2; | 11 | const expo2 = @import("expo2.zig").expo2; |
| 11 | 12 | ||
| 12 | pub fn sinh(x: var) -> @typeOf(x) { | 13 | pub fn sinh(x: var) -> @typeOf(x) { |
std/math/sqrt.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - sqrt(x) = nan if x < 0 | 5 | // - sqrt(x) = nan if x < 0 |
| 6 | // - sqrt(nan) = nan | 6 | // - sqrt(nan) = nan |
| 7 | 7 | ||
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | const builtin = @import("builtin"); | 11 | const builtin = @import("builtin"); |
| 11 | const TypeId = builtin.TypeId; | 12 | const TypeId = builtin.TypeId; |
| 12 | 13 |
std/math/tan.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - tan(nan) = nan | 5 | // - tan(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | 11 | ||
| 11 | pub fn tan(x: var) -> @typeOf(x) { | 12 | pub fn tan(x: var) -> @typeOf(x) { |
| 12 | const T = @typeOf(x); | 13 | const T = @typeOf(x); |
std/math/tanh.zig+3-2| ... | @@ -5,8 +5,9 @@ | ... | @@ -5,8 +5,9 @@ |
| 5 | // - sinh(nan) = nan | 5 | // - sinh(nan) = nan |
| 6 | 6 | ||
| 7 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 8 | const math = @import("index.zig"); | 8 | const std = @import("../index.zig"); |
| 9 | const assert = @import("../debug.zig").assert; | 9 | const math = std.math; |
| 10 | const assert = std.debug.assert; | ||
| 10 | const expo2 = @import("expo2.zig").expo2; | 11 | const expo2 = @import("expo2.zig").expo2; |
| 11 | 12 | ||
| 12 | pub fn tanh(x: var) -> @typeOf(x) { | 13 | pub fn tanh(x: var) -> @typeOf(x) { |
std/math/trunc.zig+3-2| ... | @@ -4,8 +4,9 @@ | ... | @@ -4,8 +4,9 @@ |
| 4 | // - trunc(+-inf) = +-inf | 4 | // - trunc(+-inf) = +-inf |
| 5 | // - trunc(nan) = nan | 5 | // - trunc(nan) = nan |
| 6 | 6 | ||
| 7 | const math = @import("index.zig"); | 7 | const std = @import("../index.zig"); |
| 8 | const assert = @import("../debug.zig").assert; | 8 | const math = std.math; |
| 9 | const assert = std.debug.assert; | ||
| 9 | 10 | ||
| 10 | pub fn trunc(x: var) -> @typeOf(x) { | 11 | pub fn trunc(x: var) -> @typeOf(x) { |
| 11 | const T = @typeOf(x); | 12 | const T = @typeOf(x); |
std/mem.zig+3-2| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const debug = @import("debug.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const debug = std.debug; | ||
| 2 | const assert = debug.assert; | 3 | const assert = debug.assert; |
| 3 | const math = @import("math/index.zig"); | 4 | const math = std.math; |
| 4 | const builtin = @import("builtin"); | 5 | const builtin = @import("builtin"); |
| 5 | 6 | ||
| 6 | error OutOfMemory; | 7 | error OutOfMemory; |
std/net.zig+4-3| ... | @@ -1,6 +1,7 @@ | ... | @@ -1,6 +1,7 @@ |
| 1 | const linux = @import("os/linux.zig"); | 1 | const std = @import("index.zig"); |
| 2 | const assert = @import("debug.zig").assert; | 2 | const linux = std.os.linux; |
| 3 | const endian = @import("endian.zig"); | 3 | const assert = std.debug.assert; |
| 4 | const endian = std.endian; | ||
| 4 | 5 | ||
| 5 | error SigInterrupt; | 6 | error SigInterrupt; |
| 6 | error Io; | 7 | error Io; |
std/os/darwin.zig+3-2| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const c = @import("../c/index.zig"); | 1 | const std = @import("../index.zig"); |
| 2 | const assert = @import("../debug.zig").assert; | 2 | const c = std.c; |
| 3 | const assert = std.debug.assert; | ||
| 3 | 4 | ||
| 4 | pub use @import("darwin_errno.zig"); | 5 | pub use @import("darwin_errno.zig"); |
| 5 | 6 |
std/os/index.zig+11-10| ... | @@ -1,3 +1,4 @@ | ... | @@ -1,3 +1,4 @@ |
| 1 | const std = @import("../index.zig"); | ||
| 1 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 2 | const Os = builtin.Os; | 3 | const Os = builtin.Os; |
| 3 | const is_windows = builtin.os == Os.windows; | 4 | const is_windows = builtin.os == Os.windows; |
| ... | @@ -37,22 +38,22 @@ pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; | ... | @@ -37,22 +38,22 @@ pub const createWindowsEnvBlock = windows_util.createWindowsEnvBlock; |
| 37 | 38 | ||
| 38 | pub const FileHandle = if (is_windows) windows.HANDLE else i32; | 39 | pub const FileHandle = if (is_windows) windows.HANDLE else i32; |
| 39 | 40 | ||
| 40 | const debug = @import("../debug.zig"); | 41 | const debug = std.debug; |
| 41 | const assert = debug.assert; | 42 | const assert = debug.assert; |
| 42 | 43 | ||
| 43 | const c = @import("../c/index.zig"); | 44 | const c = std.c; |
| 44 | 45 | ||
| 45 | const mem = @import("../mem.zig"); | 46 | const mem = std.mem; |
| 46 | const Allocator = mem.Allocator; | 47 | const Allocator = mem.Allocator; |
| 47 | 48 | ||
| 48 | const BufMap = @import("../buf_map.zig").BufMap; | 49 | const BufMap = std.BufMap; |
| 49 | const cstr = @import("../cstr.zig"); | 50 | const cstr = std.cstr; |
| 50 | 51 | ||
| 51 | const io = @import("../io.zig"); | 52 | const io = std.io; |
| 52 | const base64 = @import("../base64.zig"); | 53 | const base64 = std.base64; |
| 53 | const ArrayList = @import("../array_list.zig").ArrayList; | 54 | const ArrayList = std.ArrayList; |
| 54 | const Buffer = @import("../buffer.zig").Buffer; | 55 | const Buffer = std.Buffer; |
| 55 | const math = @import("../index.zig").math; | 56 | const math = std.math; |
| 56 | 57 | ||
| 57 | error SystemResources; | 58 | error SystemResources; |
| 58 | error AccessDenied; | 59 | error AccessDenied; |
std/os/linux.zig+2-1| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | const assert = @import("../debug.zig").assert; | 1 | const std = @import("../index.zig"); |
| 2 | const assert = std.debug.assert; | ||
| 2 | const builtin = @import("builtin"); | 3 | const builtin = @import("builtin"); |
| 3 | const arch = switch (builtin.arch) { | 4 | const arch = switch (builtin.arch) { |
| 4 | builtin.Arch.x86_64 => @import("linux_x86_64.zig"), | 5 | builtin.Arch.x86_64 => @import("linux_x86_64.zig"), |
std/os/path.zig+7-7| ... | @@ -1,16 +1,16 @@ | ... | @@ -1,16 +1,16 @@ |
| 1 | const std = @import("../index.zig"); | ||
| 1 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 2 | const Os = builtin.Os; | 3 | const Os = builtin.Os; |
| 3 | const debug = @import("../debug.zig"); | 4 | const debug = std.debug; |
| 4 | const assert = debug.assert; | 5 | const assert = debug.assert; |
| 5 | const mem = @import("../mem.zig"); | 6 | const mem = std.mem; |
| 6 | const fmt = @import("../fmt/index.zig"); | 7 | const fmt = std.fmt; |
| 7 | const Allocator = mem.Allocator; | 8 | const Allocator = mem.Allocator; |
| 8 | const os = @import("index.zig"); | 9 | const os = std.os; |
| 9 | const math = @import("../math/index.zig"); | 10 | const math = std.math; |
| 10 | const posix = os.posix; | 11 | const posix = os.posix; |
| 11 | const windows = os.windows; | 12 | const windows = os.windows; |
| 12 | const c = @import("../c/index.zig"); | 13 | const cstr = std.cstr; |
| 13 | const cstr = @import("../cstr.zig"); | ||
| 14 | 14 | ||
| 15 | pub const sep_windows = '\\'; | 15 | pub const sep_windows = '\\'; |
| 16 | pub const sep_posix = '/'; | 16 | pub const sep_posix = '/'; |
std/rand.zig+4-3| ... | @@ -1,8 +1,9 @@ | ... | @@ -1,8 +1,9 @@ |
| 1 | const std = @import("index.zig"); | ||
| 1 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 2 | const assert = @import("debug.zig").assert; | 3 | const assert = std.debug.assert; |
| 3 | const rand_test = @import("rand_test.zig"); | 4 | const rand_test = @import("rand_test.zig"); |
| 4 | const mem = @import("mem.zig"); | 5 | const mem = std.mem; |
| 5 | const math = @import("math/index.zig"); | 6 | const math = std.math; |
| 6 | 7 | ||
| 7 | pub const MT19937_32 = MersenneTwister( | 8 | pub const MT19937_32 = MersenneTwister( |
| 8 | u32, 624, 397, 31, | 9 | u32, 624, 397, 31, |
std/special/compiler_rt/fixunsdfdi_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi; | 1 | const __fixunsdfdi = @import("fixunsdfdi.zig").__fixunsdfdi; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunsdfdi(a: f64, expected: u64) { | 4 | fn test__fixunsdfdi(a: f64, expected: u64) { |
| 5 | const x = __fixunsdfdi(a); | 5 | const x = __fixunsdfdi(a); |
std/special/compiler_rt/fixunsdfsi_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi; | 1 | const __fixunsdfsi = @import("fixunsdfsi.zig").__fixunsdfsi; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunsdfsi(a: f64, expected: u32) { | 4 | fn test__fixunsdfsi(a: f64, expected: u32) { |
| 5 | const x = __fixunsdfsi(a); | 5 | const x = __fixunsdfsi(a); |
std/special/compiler_rt/fixunsdfti_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti; | 1 | const __fixunsdfti = @import("fixunsdfti.zig").__fixunsdfti; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunsdfti(a: f64, expected: u128) { | 4 | fn test__fixunsdfti(a: f64, expected: u128) { |
| 5 | const x = __fixunsdfti(a); | 5 | const x = __fixunsdfti(a); |
std/special/compiler_rt/fixunssfdi_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; | 1 | const __fixunssfdi = @import("fixunssfdi.zig").__fixunssfdi; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunssfdi(a: f32, expected: u64) { | 4 | fn test__fixunssfdi(a: f32, expected: u64) { |
| 5 | const x = __fixunssfdi(a); | 5 | const x = __fixunssfdi(a); |
std/special/compiler_rt/fixunssfsi_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi; | 1 | const __fixunssfsi = @import("fixunssfsi.zig").__fixunssfsi; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunssfsi(a: f32, expected: u32) { | 4 | fn test__fixunssfsi(a: f32, expected: u32) { |
| 5 | const x = __fixunssfsi(a); | 5 | const x = __fixunssfsi(a); |
std/special/compiler_rt/fixunssfti_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; | 1 | const __fixunssfti = @import("fixunssfti.zig").__fixunssfti; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunssfti(a: f32, expected: u128) { | 4 | fn test__fixunssfti(a: f32, expected: u128) { |
| 5 | const x = __fixunssfti(a); | 5 | const x = __fixunssfti(a); |
std/special/compiler_rt/fixunstfdi_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi; | 1 | const __fixunstfdi = @import("fixunstfdi.zig").__fixunstfdi; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunstfdi(a: f128, expected: u64) { | 4 | fn test__fixunstfdi(a: f128, expected: u64) { |
| 5 | const x = __fixunstfdi(a); | 5 | const x = __fixunstfdi(a); |
std/special/compiler_rt/fixunstfsi_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi; | 1 | const __fixunstfsi = @import("fixunstfsi.zig").__fixunstfsi; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunstfsi(a: f128, expected: u32) { | 4 | fn test__fixunstfsi(a: f128, expected: u32) { |
| 5 | const x = __fixunstfsi(a); | 5 | const x = __fixunstfsi(a); |
std/special/compiler_rt/fixunstfti_test.zig+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const __fixunstfti = @import("fixunstfti.zig").__fixunstfti; | 1 | const __fixunstfti = @import("fixunstfti.zig").__fixunstfti; |
| 2 | const assert = @import("../../debug.zig").assert; | 2 | const assert = @import("../../index.zig").debug.assert; |
| 3 | 3 | ||
| 4 | fn test__fixunstfti(a: f128, expected: u128) { | 4 | fn test__fixunstfti(a: f128, expected: u128) { |
| 5 | const x = __fixunstfti(a); | 5 | const x = __fixunstfti(a); |
std/special/compiler_rt/index.zig+1-1| ... | @@ -68,7 +68,7 @@ comptime { | ... | @@ -68,7 +68,7 @@ comptime { |
| 68 | } | 68 | } |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | const assert = @import("../../debug.zig").assert; | 71 | const assert = @import("../../index.zig").debug.assert; |
| 72 | 72 | ||
| 73 | const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; | 73 | const __udivmoddi4 = @import("udivmoddi4.zig").__udivmoddi4; |
| 74 | 74 |
test/cases/union.zig+15| ... | @@ -220,3 +220,18 @@ fn assertIsTheUnion2Item1(value: &const TheUnion2) { | ... | @@ -220,3 +220,18 @@ fn assertIsTheUnion2Item1(value: &const TheUnion2) { |
| 220 | assert(*value == TheUnion2.Item1); | 220 | assert(*value == TheUnion2.Item1); |
| 221 | } | 221 | } |
| 222 | 222 | ||
| 223 | |||
| 224 | pub const PackThis = union(enum) { | ||
| 225 | Invalid: bool, | ||
| 226 | StringLiteral: u2, | ||
| 227 | }; | ||
| 228 | |||
| 229 | test "constant packed union" { | ||
| 230 | testConstPackedUnion([]PackThis { | ||
| 231 | PackThis { .StringLiteral = 1 }, | ||
| 232 | }); | ||
| 233 | } | ||
| 234 | |||
| 235 | fn testConstPackedUnion(expected_tokens: []const PackThis) { | ||
| 236 | assert(expected_tokens[0].StringLiteral == 1); | ||
| 237 | } |