| author | |
| committer | |
| log | f0ec308e26ff957c7fbb50ccc69d3d549c42c4da |
| tree | 5fbb35b30640f8c4fd616c3132d556af9a3bc11c |
| parent | 11e8afb37cea3d4b951165f382eeee36a653978f |
| parent | 5f5364ad73dc6c31e1e189596f407970f852701a |
| signature |
Refresh from original.20 files changed, 813 insertions(+), 294 deletions(-)
CMakeLists.txt+1| ... | @@ -491,6 +491,7 @@ set(ZIG_STD_FILES | ... | @@ -491,6 +491,7 @@ set(ZIG_STD_FILES |
| 491 | "heap.zig" | 491 | "heap.zig" |
| 492 | "index.zig" | 492 | "index.zig" |
| 493 | "io.zig" | 493 | "io.zig" |
| 494 | "io/seekable_stream.zig" | ||
| 494 | "json.zig" | 495 | "json.zig" |
| 495 | "lazy_init.zig" | 496 | "lazy_init.zig" |
| 496 | "linked_list.zig" | 497 | "linked_list.zig" |
ci/azure/linux_script+3| ... | @@ -34,6 +34,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then | ... | @@ -34,6 +34,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then |
| 34 | 34 | ||
| 35 | SHASUM=$(sha256sum $ARTIFACTSDIR/$TARBALL | cut '-d ' -f1) | 35 | SHASUM=$(sha256sum $ARTIFACTSDIR/$TARBALL | cut '-d ' -f1) |
| 36 | BYTESIZE=$(wc -c < $ARTIFACTSDIR/$TARBALL) | 36 | BYTESIZE=$(wc -c < $ARTIFACTSDIR/$TARBALL) |
| 37 | # `set -x` causes these variables to be mangled. | ||
| 38 | # See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html | ||
| 39 | set +x | ||
| 37 | echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL" | 40 | echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL" |
| 38 | echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM" | 41 | echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM" |
| 39 | echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE" | 42 | echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE" |
ci/azure/macos_script+3| ... | @@ -98,6 +98,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then | ... | @@ -98,6 +98,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then |
| 98 | 98 | ||
| 99 | SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1) | 99 | SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1) |
| 100 | BYTESIZE=$(wc -c < $TARBALL) | 100 | BYTESIZE=$(wc -c < $TARBALL) |
| 101 | # `set -x` causes these variables to be mangled. | ||
| 102 | # See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html | ||
| 103 | set +x | ||
| 101 | echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL" | 104 | echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL" |
| 102 | echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM" | 105 | echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM" |
| 103 | echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE" | 106 | echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE" |
ci/azure/windows_upload+3| ... | @@ -25,6 +25,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then | ... | @@ -25,6 +25,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then |
| 25 | 25 | ||
| 26 | SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1) | 26 | SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1) |
| 27 | BYTESIZE=$(wc -c < $TARBALL) | 27 | BYTESIZE=$(wc -c < $TARBALL) |
| 28 | # `set -x` causes these variables to be mangled. | ||
| 29 | # See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html | ||
| 30 | set +x | ||
| 28 | echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL" | 31 | echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL" |
| 29 | echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM" | 32 | echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM" |
| 30 | echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE" | 33 | echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE" |
deps/lld/ELF/OutputSections.cpp+1-1| ... | @@ -95,7 +95,7 @@ void OutputSection::addSection(InputSection *IS) { | ... | @@ -95,7 +95,7 @@ void OutputSection::addSection(InputSection *IS) { |
| 95 | Flags = IS->Flags; | 95 | Flags = IS->Flags; |
| 96 | } else { | 96 | } else { |
| 97 | // Otherwise, check if new type or flags are compatible with existing ones. | 97 | // Otherwise, check if new type or flags are compatible with existing ones. |
| 98 | unsigned Mask = SHF_ALLOC | SHF_TLS | SHF_LINK_ORDER; | 98 | unsigned Mask = SHF_TLS | SHF_LINK_ORDER; |
| 99 | if ((Flags & Mask) != (IS->Flags & Mask)) | 99 | if ((Flags & Mask) != (IS->Flags & Mask)) |
| 100 | error("incompatible section flags for " + Name + "\n>>> " + toString(IS) + | 100 | error("incompatible section flags for " + Name + "\n>>> " + toString(IS) + |
| 101 | ": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name + | 101 | ": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name + |
doc/langref.html.in+19-5| ... | @@ -8,7 +8,13 @@ | ... | @@ -8,7 +8,13 @@ |
| 8 | body{ | 8 | body{ |
| 9 | background-color:#111; | 9 | background-color:#111; |
| 10 | color: #bbb; | 10 | color: #bbb; |
| 11 | font-family: sans-serif; | 11 | font-family: system-ui, |
| 12 | /* Fallbacks for browsers that don't support system-ui */ | ||
| 13 | /* https://caniuse.com/#search=system-ui */ | ||
| 14 | -apple-system, /* iOS and macOS */ | ||
| 15 | Roboto, /* Android */ | ||
| 16 | "Segoe UI", /* Windows */ | ||
| 17 | sans-serif; | ||
| 12 | } | 18 | } |
| 13 | a { | 19 | a { |
| 14 | color: #88f; | 20 | color: #88f; |
| ... | @@ -4264,13 +4270,21 @@ fn foo() i32 { | ... | @@ -4264,13 +4270,21 @@ fn foo() i32 { |
| 4264 | return 1234; | 4270 | return 1234; |
| 4265 | } | 4271 | } |
| 4266 | {#code_end#} | 4272 | {#code_end#} |
| 4267 | <p>However, if the expression has type {#syntax#}void{#endsyntax#}:</p> | 4273 | <p>However, if the expression has type {#syntax#}void{#endsyntax#}, there will be no error. Function return values can also be explicitly ignored by assigning them to {#syntax#}_{#endsyntax#}. </p> |
| 4268 | {#code_begin|test#} | 4274 | {#code_begin|test#} |
| 4269 | test "ignoring expression value" { | 4275 | test "void is ignored" { |
| 4270 | foo(); | 4276 | returnsVoid(); |
| 4277 | } | ||
| 4278 | |||
| 4279 | test "explicitly ignoring expression value" { | ||
| 4280 | _ = foo(); | ||
| 4271 | } | 4281 | } |
| 4272 | 4282 | ||
| 4273 | fn foo() void {} | 4283 | fn returnsVoid() void {} |
| 4284 | |||
| 4285 | fn foo() i32 { | ||
| 4286 | return 1234; | ||
| 4287 | } | ||
| 4274 | {#code_end#} | 4288 | {#code_end#} |
| 4275 | {#header_close#} | 4289 | {#header_close#} |
| 4276 | 4290 |
example/guess_number/main.zig+4-4| ... | @@ -24,15 +24,15 @@ pub fn main() !void { | ... | @@ -24,15 +24,15 @@ pub fn main() !void { |
| 24 | try stdout.print("\nGuess a number between 1 and 100: "); | 24 | try stdout.print("\nGuess a number between 1 and 100: "); |
| 25 | var line_buf: [20]u8 = undefined; | 25 | var line_buf: [20]u8 = undefined; |
| 26 | 26 | ||
| 27 | const line_len = io.readLine(line_buf[0..]) catch |err| switch (err) { | 27 | const line = io.readLineSlice(line_buf[0..]) catch |err| switch (err) { |
| 28 | error.InputTooLong => { | 28 | error.OutOfMemory => { |
| 29 | try stdout.print("Input too long.\n"); | 29 | try stdout.print("Input too long.\n"); |
| 30 | continue; | 30 | continue; |
| 31 | }, | 31 | }, |
| 32 | error.EndOfFile, error.StdInUnavailable => return err, | 32 | else => return err, |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | const guess = fmt.parseUnsigned(u8, line_buf[0..line_len], 10) catch { | 35 | const guess = fmt.parseUnsigned(u8, line, 10) catch { |
| 36 | try stdout.print("Invalid number.\n"); | 36 | try stdout.print("Invalid number.\n"); |
| 37 | continue; | 37 | continue; |
| 38 | }; | 38 | }; |
src/ir.cpp+13-1| ... | @@ -67,6 +67,8 @@ enum ConstCastResultId { | ... | @@ -67,6 +67,8 @@ enum ConstCastResultId { |
| 67 | struct ConstCastOnly; | 67 | struct ConstCastOnly; |
| 68 | struct ConstCastArg { | 68 | struct ConstCastArg { |
| 69 | size_t arg_index; | 69 | size_t arg_index; |
| 70 | ZigType *actual_param_type; | ||
| 71 | ZigType *expected_param_type; | ||
| 70 | ConstCastOnly *child; | 72 | ConstCastOnly *child; |
| 71 | }; | 73 | }; |
| 72 | 74 | ||
| ... | @@ -8638,6 +8640,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted | ... | @@ -8638,6 +8640,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted |
| 8638 | if (arg_child.id != ConstCastResultIdOk) { | 8640 | if (arg_child.id != ConstCastResultIdOk) { |
| 8639 | result.id = ConstCastResultIdFnArg; | 8641 | result.id = ConstCastResultIdFnArg; |
| 8640 | result.data.fn_arg.arg_index = i; | 8642 | result.data.fn_arg.arg_index = i; |
| 8643 | result.data.fn_arg.actual_param_type = actual_param_info->type; | ||
| 8644 | result.data.fn_arg.expected_param_type = expected_param_info->type; | ||
| 8641 | result.data.fn_arg.child = allocate_nonzero<ConstCastOnly>(1); | 8645 | result.data.fn_arg.child = allocate_nonzero<ConstCastOnly>(1); |
| 8642 | *result.data.fn_arg.child = arg_child; | 8646 | *result.data.fn_arg.child = arg_child; |
| 8643 | return result; | 8647 | return result; |
| ... | @@ -10483,6 +10487,15 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa | ... | @@ -10483,6 +10487,15 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa |
| 10483 | } | 10487 | } |
| 10484 | break; | 10488 | break; |
| 10485 | } | 10489 | } |
| 10490 | case ConstCastResultIdFnArg: { | ||
| 10491 | ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node, | ||
| 10492 | buf_sprintf("parameter %" ZIG_PRI_usize ": '%s' cannot cast into '%s'", | ||
| 10493 | cast_result->data.fn_arg.arg_index, | ||
| 10494 | buf_ptr(&cast_result->data.fn_arg.actual_param_type->name), | ||
| 10495 | buf_ptr(&cast_result->data.fn_arg.expected_param_type->name))); | ||
| 10496 | report_recursive_error(ira, source_node, cast_result->data.fn_arg.child, msg); | ||
| 10497 | break; | ||
| 10498 | } | ||
| 10486 | case ConstCastResultIdFnAlign: // TODO | 10499 | case ConstCastResultIdFnAlign: // TODO |
| 10487 | case ConstCastResultIdFnCC: // TODO | 10500 | case ConstCastResultIdFnCC: // TODO |
| 10488 | case ConstCastResultIdFnVarArgs: // TODO | 10501 | case ConstCastResultIdFnVarArgs: // TODO |
| ... | @@ -10490,7 +10503,6 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa | ... | @@ -10490,7 +10503,6 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa |
| 10490 | case ConstCastResultIdFnReturnType: // TODO | 10503 | case ConstCastResultIdFnReturnType: // TODO |
| 10491 | case ConstCastResultIdFnArgCount: // TODO | 10504 | case ConstCastResultIdFnArgCount: // TODO |
| 10492 | case ConstCastResultIdFnGenericArgCount: // TODO | 10505 | case ConstCastResultIdFnGenericArgCount: // TODO |
| 10493 | case ConstCastResultIdFnArg: // TODO | ||
| 10494 | case ConstCastResultIdFnArgNoAlias: // TODO | 10506 | case ConstCastResultIdFnArgNoAlias: // TODO |
| 10495 | case ConstCastResultIdUnresolvedInferredErrSet: // TODO | 10507 | case ConstCastResultIdUnresolvedInferredErrSet: // TODO |
| 10496 | case ConstCastResultIdAsyncAllocatorType: // TODO | 10508 | case ConstCastResultIdAsyncAllocatorType: // TODO |
src/zig_llvm.cpp+163-12| ... | @@ -681,18 +681,6 @@ void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) { | ... | @@ -681,18 +681,6 @@ void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) { |
| 681 | } | 681 | } |
| 682 | 682 | ||
| 683 | 683 | ||
| 684 | static_assert((Triple::ArchType)ZigLLVM_LastArchType == Triple::LastArchType, ""); | ||
| 685 | static_assert((Triple::VendorType)ZigLLVM_LastVendorType == Triple::LastVendorType, ""); | ||
| 686 | static_assert((Triple::OSType)ZigLLVM_LastOSType == Triple::LastOSType, ""); | ||
| 687 | static_assert((Triple::EnvironmentType)ZigLLVM_LastEnvironmentType == Triple::LastEnvironmentType, ""); | ||
| 688 | static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v5 == Triple::KalimbaSubArch_v5, ""); | ||
| 689 | |||
| 690 | static_assert((Triple::ObjectFormatType)ZigLLVM_UnknownObjectFormat == Triple::UnknownObjectFormat, ""); | ||
| 691 | static_assert((Triple::ObjectFormatType)ZigLLVM_COFF == Triple::COFF, ""); | ||
| 692 | static_assert((Triple::ObjectFormatType)ZigLLVM_ELF == Triple::ELF, ""); | ||
| 693 | static_assert((Triple::ObjectFormatType)ZigLLVM_MachO == Triple::MachO, ""); | ||
| 694 | static_assert((Triple::ObjectFormatType)ZigLLVM_Wasm == Triple::Wasm, ""); | ||
| 695 | |||
| 696 | const char *ZigLLVMGetArchTypeName(ZigLLVM_ArchType arch) { | 684 | const char *ZigLLVMGetArchTypeName(ZigLLVM_ArchType arch) { |
| 697 | return (const char*)Triple::getArchTypeName((Triple::ArchType)arch).bytes_begin(); | 685 | return (const char*)Triple::getArchTypeName((Triple::ArchType)arch).bytes_begin(); |
| 698 | } | 686 | } |
| ... | @@ -919,3 +907,166 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_ | ... | @@ -919,3 +907,166 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_ |
| 919 | assert(false); // unreachable | 907 | assert(false); // unreachable |
| 920 | abort(); | 908 | abort(); |
| 921 | } | 909 | } |
| 910 | |||
| 911 | static_assert((Triple::ArchType)ZigLLVM_UnknownArch == Triple::UnknownArch, ""); | ||
| 912 | static_assert((Triple::ArchType)ZigLLVM_arm == Triple::arm, ""); | ||
| 913 | static_assert((Triple::ArchType)ZigLLVM_armeb == Triple::armeb, ""); | ||
| 914 | static_assert((Triple::ArchType)ZigLLVM_aarch64 == Triple::aarch64, ""); | ||
| 915 | static_assert((Triple::ArchType)ZigLLVM_aarch64_be == Triple::aarch64_be, ""); | ||
| 916 | static_assert((Triple::ArchType)ZigLLVM_arc == Triple::arc, ""); | ||
| 917 | static_assert((Triple::ArchType)ZigLLVM_avr == Triple::avr, ""); | ||
| 918 | static_assert((Triple::ArchType)ZigLLVM_bpfel == Triple::bpfel, ""); | ||
| 919 | static_assert((Triple::ArchType)ZigLLVM_bpfeb == Triple::bpfeb, ""); | ||
| 920 | static_assert((Triple::ArchType)ZigLLVM_hexagon == Triple::hexagon, ""); | ||
| 921 | static_assert((Triple::ArchType)ZigLLVM_mips == Triple::mips, ""); | ||
| 922 | static_assert((Triple::ArchType)ZigLLVM_mipsel == Triple::mipsel, ""); | ||
| 923 | static_assert((Triple::ArchType)ZigLLVM_mips64 == Triple::mips64, ""); | ||
| 924 | static_assert((Triple::ArchType)ZigLLVM_mips64el == Triple::mips64el, ""); | ||
| 925 | static_assert((Triple::ArchType)ZigLLVM_msp430 == Triple::msp430, ""); | ||
| 926 | static_assert((Triple::ArchType)ZigLLVM_nios2 == Triple::nios2, ""); | ||
| 927 | static_assert((Triple::ArchType)ZigLLVM_ppc == Triple::ppc, ""); | ||
| 928 | static_assert((Triple::ArchType)ZigLLVM_ppc64 == Triple::ppc64, ""); | ||
| 929 | static_assert((Triple::ArchType)ZigLLVM_ppc64le == Triple::ppc64le, ""); | ||
| 930 | static_assert((Triple::ArchType)ZigLLVM_r600 == Triple::r600, ""); | ||
| 931 | static_assert((Triple::ArchType)ZigLLVM_amdgcn == Triple::amdgcn, ""); | ||
| 932 | static_assert((Triple::ArchType)ZigLLVM_riscv32 == Triple::riscv32, ""); | ||
| 933 | static_assert((Triple::ArchType)ZigLLVM_riscv64 == Triple::riscv64, ""); | ||
| 934 | static_assert((Triple::ArchType)ZigLLVM_sparc == Triple::sparc, ""); | ||
| 935 | static_assert((Triple::ArchType)ZigLLVM_sparcv9 == Triple::sparcv9, ""); | ||
| 936 | static_assert((Triple::ArchType)ZigLLVM_sparcel == Triple::sparcel, ""); | ||
| 937 | static_assert((Triple::ArchType)ZigLLVM_systemz == Triple::systemz, ""); | ||
| 938 | static_assert((Triple::ArchType)ZigLLVM_tce == Triple::tce, ""); | ||
| 939 | static_assert((Triple::ArchType)ZigLLVM_tcele == Triple::tcele, ""); | ||
| 940 | static_assert((Triple::ArchType)ZigLLVM_thumb == Triple::thumb, ""); | ||
| 941 | static_assert((Triple::ArchType)ZigLLVM_thumbeb == Triple::thumbeb, ""); | ||
| 942 | static_assert((Triple::ArchType)ZigLLVM_x86 == Triple::x86, ""); | ||
| 943 | static_assert((Triple::ArchType)ZigLLVM_x86_64 == Triple::x86_64, ""); | ||
| 944 | static_assert((Triple::ArchType)ZigLLVM_xcore == Triple::xcore, ""); | ||
| 945 | static_assert((Triple::ArchType)ZigLLVM_nvptx == Triple::nvptx, ""); | ||
| 946 | static_assert((Triple::ArchType)ZigLLVM_nvptx64 == Triple::nvptx64, ""); | ||
| 947 | static_assert((Triple::ArchType)ZigLLVM_le32 == Triple::le32, ""); | ||
| 948 | static_assert((Triple::ArchType)ZigLLVM_le64 == Triple::le64, ""); | ||
| 949 | static_assert((Triple::ArchType)ZigLLVM_amdil == Triple::amdil, ""); | ||
| 950 | static_assert((Triple::ArchType)ZigLLVM_amdil64 == Triple::amdil64, ""); | ||
| 951 | static_assert((Triple::ArchType)ZigLLVM_hsail == Triple::hsail, ""); | ||
| 952 | static_assert((Triple::ArchType)ZigLLVM_hsail64 == Triple::hsail64, ""); | ||
| 953 | static_assert((Triple::ArchType)ZigLLVM_spir == Triple::spir, ""); | ||
| 954 | static_assert((Triple::ArchType)ZigLLVM_spir64 == Triple::spir64, ""); | ||
| 955 | static_assert((Triple::ArchType)ZigLLVM_kalimba == Triple::kalimba, ""); | ||
| 956 | static_assert((Triple::ArchType)ZigLLVM_shave == Triple::shave, ""); | ||
| 957 | static_assert((Triple::ArchType)ZigLLVM_lanai == Triple::lanai, ""); | ||
| 958 | static_assert((Triple::ArchType)ZigLLVM_wasm32 == Triple::wasm32, ""); | ||
| 959 | static_assert((Triple::ArchType)ZigLLVM_wasm64 == Triple::wasm64, ""); | ||
| 960 | static_assert((Triple::ArchType)ZigLLVM_renderscript32 == Triple::renderscript32, ""); | ||
| 961 | static_assert((Triple::ArchType)ZigLLVM_renderscript64 == Triple::renderscript64, ""); | ||
| 962 | // Uncomment this when testing LLVM 8.0.0 | ||
| 963 | //static_assert((Triple::ArchType)ZigLLVM_LastArchType == Triple::LastArchType, ""); | ||
| 964 | |||
| 965 | static_assert((Triple::SubArchType)ZigLLVM_NoSubArch == Triple::NoSubArch, ""); | ||
| 966 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_4a == Triple::ARMSubArch_v8_4a, ""); | ||
| 967 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_3a == Triple::ARMSubArch_v8_3a, ""); | ||
| 968 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_2a == Triple::ARMSubArch_v8_2a, ""); | ||
| 969 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_1a == Triple::ARMSubArch_v8_1a, ""); | ||
| 970 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8 == Triple::ARMSubArch_v8, ""); | ||
| 971 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8r == Triple::ARMSubArch_v8r, ""); | ||
| 972 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8m_baseline == Triple::ARMSubArch_v8m_baseline, ""); | ||
| 973 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8m_mainline == Triple::ARMSubArch_v8m_mainline, ""); | ||
| 974 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7 == Triple::ARMSubArch_v7, ""); | ||
| 975 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7em == Triple::ARMSubArch_v7em, ""); | ||
| 976 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7m == Triple::ARMSubArch_v7m, ""); | ||
| 977 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7s == Triple::ARMSubArch_v7s, ""); | ||
| 978 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7k == Triple::ARMSubArch_v7k, ""); | ||
| 979 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7ve == Triple::ARMSubArch_v7ve, ""); | ||
| 980 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6 == Triple::ARMSubArch_v6, ""); | ||
| 981 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6m == Triple::ARMSubArch_v6m, ""); | ||
| 982 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6k == Triple::ARMSubArch_v6k, ""); | ||
| 983 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6t2 == Triple::ARMSubArch_v6t2, ""); | ||
| 984 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v5 == Triple::ARMSubArch_v5, ""); | ||
| 985 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v5te == Triple::ARMSubArch_v5te, ""); | ||
| 986 | static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v4t == Triple::ARMSubArch_v4t, ""); | ||
| 987 | static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v3 == Triple::KalimbaSubArch_v3, ""); | ||
| 988 | static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v4 == Triple::KalimbaSubArch_v4, ""); | ||
| 989 | static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v5 == Triple::KalimbaSubArch_v5, ""); | ||
| 990 | |||
| 991 | static_assert((Triple::VendorType)ZigLLVM_UnknownVendor == Triple::UnknownVendor, ""); | ||
| 992 | static_assert((Triple::VendorType)ZigLLVM_Apple == Triple::Apple, ""); | ||
| 993 | static_assert((Triple::VendorType)ZigLLVM_PC == Triple::PC, ""); | ||
| 994 | static_assert((Triple::VendorType)ZigLLVM_SCEI == Triple::SCEI, ""); | ||
| 995 | static_assert((Triple::VendorType)ZigLLVM_BGP == Triple::BGP, ""); | ||
| 996 | static_assert((Triple::VendorType)ZigLLVM_BGQ == Triple::BGQ, ""); | ||
| 997 | static_assert((Triple::VendorType)ZigLLVM_Freescale == Triple::Freescale, ""); | ||
| 998 | static_assert((Triple::VendorType)ZigLLVM_IBM == Triple::IBM, ""); | ||
| 999 | static_assert((Triple::VendorType)ZigLLVM_ImaginationTechnologies == Triple::ImaginationTechnologies, ""); | ||
| 1000 | static_assert((Triple::VendorType)ZigLLVM_MipsTechnologies == Triple::MipsTechnologies, ""); | ||
| 1001 | static_assert((Triple::VendorType)ZigLLVM_NVIDIA == Triple::NVIDIA, ""); | ||
| 1002 | static_assert((Triple::VendorType)ZigLLVM_CSR == Triple::CSR, ""); | ||
| 1003 | static_assert((Triple::VendorType)ZigLLVM_Myriad == Triple::Myriad, ""); | ||
| 1004 | static_assert((Triple::VendorType)ZigLLVM_AMD == Triple::AMD, ""); | ||
| 1005 | static_assert((Triple::VendorType)ZigLLVM_Mesa == Triple::Mesa, ""); | ||
| 1006 | static_assert((Triple::VendorType)ZigLLVM_SUSE == Triple::SUSE, ""); | ||
| 1007 | static_assert((Triple::VendorType)ZigLLVM_OpenEmbedded == Triple::OpenEmbedded, ""); | ||
| 1008 | // Uncomment this when testing LLVM 8.0.0 | ||
| 1009 | //static_assert((Triple::VendorType)ZigLLVM_LastVendorType == Triple::LastVendorType, ""); | ||
| 1010 | |||
| 1011 | static_assert((Triple::OSType)ZigLLVM_UnknownOS == Triple::UnknownOS, ""); | ||
| 1012 | static_assert((Triple::OSType)ZigLLVM_Ananas == Triple::Ananas, ""); | ||
| 1013 | static_assert((Triple::OSType)ZigLLVM_CloudABI == Triple::CloudABI, ""); | ||
| 1014 | static_assert((Triple::OSType)ZigLLVM_Darwin == Triple::Darwin, ""); | ||
| 1015 | static_assert((Triple::OSType)ZigLLVM_DragonFly == Triple::DragonFly, ""); | ||
| 1016 | static_assert((Triple::OSType)ZigLLVM_FreeBSD == Triple::FreeBSD, ""); | ||
| 1017 | static_assert((Triple::OSType)ZigLLVM_Fuchsia == Triple::Fuchsia, ""); | ||
| 1018 | static_assert((Triple::OSType)ZigLLVM_IOS == Triple::IOS, ""); | ||
| 1019 | static_assert((Triple::OSType)ZigLLVM_KFreeBSD == Triple::KFreeBSD, ""); | ||
| 1020 | static_assert((Triple::OSType)ZigLLVM_Linux == Triple::Linux, ""); | ||
| 1021 | static_assert((Triple::OSType)ZigLLVM_Lv2 == Triple::Lv2, ""); | ||
| 1022 | static_assert((Triple::OSType)ZigLLVM_MacOSX == Triple::MacOSX, ""); | ||
| 1023 | static_assert((Triple::OSType)ZigLLVM_NetBSD == Triple::NetBSD, ""); | ||
| 1024 | static_assert((Triple::OSType)ZigLLVM_OpenBSD == Triple::OpenBSD, ""); | ||
| 1025 | static_assert((Triple::OSType)ZigLLVM_Solaris == Triple::Solaris, ""); | ||
| 1026 | static_assert((Triple::OSType)ZigLLVM_Win32 == Triple::Win32, ""); | ||
| 1027 | static_assert((Triple::OSType)ZigLLVM_Haiku == Triple::Haiku, ""); | ||
| 1028 | static_assert((Triple::OSType)ZigLLVM_Minix == Triple::Minix, ""); | ||
| 1029 | static_assert((Triple::OSType)ZigLLVM_RTEMS == Triple::RTEMS, ""); | ||
| 1030 | static_assert((Triple::OSType)ZigLLVM_NaCl == Triple::NaCl, ""); | ||
| 1031 | static_assert((Triple::OSType)ZigLLVM_CNK == Triple::CNK, ""); | ||
| 1032 | static_assert((Triple::OSType)ZigLLVM_AIX == Triple::AIX, ""); | ||
| 1033 | static_assert((Triple::OSType)ZigLLVM_CUDA == Triple::CUDA, ""); | ||
| 1034 | static_assert((Triple::OSType)ZigLLVM_NVCL == Triple::NVCL, ""); | ||
| 1035 | static_assert((Triple::OSType)ZigLLVM_AMDHSA == Triple::AMDHSA, ""); | ||
| 1036 | static_assert((Triple::OSType)ZigLLVM_PS4 == Triple::PS4, ""); | ||
| 1037 | static_assert((Triple::OSType)ZigLLVM_ELFIAMCU == Triple::ELFIAMCU, ""); | ||
| 1038 | static_assert((Triple::OSType)ZigLLVM_TvOS == Triple::TvOS, ""); | ||
| 1039 | static_assert((Triple::OSType)ZigLLVM_WatchOS == Triple::WatchOS, ""); | ||
| 1040 | static_assert((Triple::OSType)ZigLLVM_Mesa3D == Triple::Mesa3D, ""); | ||
| 1041 | static_assert((Triple::OSType)ZigLLVM_Contiki == Triple::Contiki, ""); | ||
| 1042 | static_assert((Triple::OSType)ZigLLVM_AMDPAL == Triple::AMDPAL, ""); | ||
| 1043 | // Uncomment this when testing LLVM 8.0.0 | ||
| 1044 | //static_assert((Triple::OSType)ZigLLVM_LastOSType == Triple::LastOSType, ""); | ||
| 1045 | |||
| 1046 | static_assert((Triple::EnvironmentType)ZigLLVM_UnknownEnvironment == Triple::UnknownEnvironment, ""); | ||
| 1047 | static_assert((Triple::EnvironmentType)ZigLLVM_GNU == Triple::GNU, ""); | ||
| 1048 | static_assert((Triple::EnvironmentType)ZigLLVM_GNUABIN32 == Triple::GNUABIN32, ""); | ||
| 1049 | static_assert((Triple::EnvironmentType)ZigLLVM_GNUABI64 == Triple::GNUABI64, ""); | ||
| 1050 | static_assert((Triple::EnvironmentType)ZigLLVM_GNUEABI == Triple::GNUEABI, ""); | ||
| 1051 | static_assert((Triple::EnvironmentType)ZigLLVM_GNUEABIHF == Triple::GNUEABIHF, ""); | ||
| 1052 | static_assert((Triple::EnvironmentType)ZigLLVM_GNUX32 == Triple::GNUX32, ""); | ||
| 1053 | static_assert((Triple::EnvironmentType)ZigLLVM_CODE16 == Triple::CODE16, ""); | ||
| 1054 | static_assert((Triple::EnvironmentType)ZigLLVM_EABI == Triple::EABI, ""); | ||
| 1055 | static_assert((Triple::EnvironmentType)ZigLLVM_EABIHF == Triple::EABIHF, ""); | ||
| 1056 | static_assert((Triple::EnvironmentType)ZigLLVM_Android == Triple::Android, ""); | ||
| 1057 | static_assert((Triple::EnvironmentType)ZigLLVM_Musl == Triple::Musl, ""); | ||
| 1058 | static_assert((Triple::EnvironmentType)ZigLLVM_MuslEABI == Triple::MuslEABI, ""); | ||
| 1059 | static_assert((Triple::EnvironmentType)ZigLLVM_MuslEABIHF == Triple::MuslEABIHF, ""); | ||
| 1060 | static_assert((Triple::EnvironmentType)ZigLLVM_MSVC == Triple::MSVC, ""); | ||
| 1061 | static_assert((Triple::EnvironmentType)ZigLLVM_Itanium == Triple::Itanium, ""); | ||
| 1062 | static_assert((Triple::EnvironmentType)ZigLLVM_Cygnus == Triple::Cygnus, ""); | ||
| 1063 | static_assert((Triple::EnvironmentType)ZigLLVM_CoreCLR == Triple::CoreCLR, ""); | ||
| 1064 | static_assert((Triple::EnvironmentType)ZigLLVM_Simulator == Triple::Simulator, ""); | ||
| 1065 | // Uncomment this when testing LLVM 8.0.0 | ||
| 1066 | //static_assert((Triple::EnvironmentType)ZigLLVM_LastEnvironmentType == Triple::LastEnvironmentType, ""); | ||
| 1067 | |||
| 1068 | static_assert((Triple::ObjectFormatType)ZigLLVM_UnknownObjectFormat == Triple::UnknownObjectFormat, ""); | ||
| 1069 | static_assert((Triple::ObjectFormatType)ZigLLVM_COFF == Triple::COFF, ""); | ||
| 1070 | static_assert((Triple::ObjectFormatType)ZigLLVM_ELF == Triple::ELF, ""); | ||
| 1071 | static_assert((Triple::ObjectFormatType)ZigLLVM_MachO == Triple::MachO, ""); | ||
| 1072 | static_assert((Triple::ObjectFormatType)ZigLLVM_Wasm == Triple::Wasm, ""); |
std/build.zig+31-8| ... | @@ -150,7 +150,11 @@ pub const Builder = struct { | ... | @@ -150,7 +150,11 @@ pub const Builder = struct { |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { | 152 | pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { |
| 153 | return LibExeObjStep.createExecutable(self, name, root_src); | 153 | return LibExeObjStep.createExecutable(self, name, root_src, false); |
| 154 | } | ||
| 155 | |||
| 156 | pub fn addStaticExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { | ||
| 157 | return LibExeObjStep.createExecutable(self, name, root_src, true); | ||
| 154 | } | 158 | } |
| 155 | 159 | ||
| 156 | pub fn addObject(self: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep { | 160 | pub fn addObject(self: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep { |
| ... | @@ -807,6 +811,11 @@ pub const Target = union(enum) { | ... | @@ -807,6 +811,11 @@ pub const Target = union(enum) { |
| 807 | } | 811 | } |
| 808 | }; | 812 | }; |
| 809 | 813 | ||
| 814 | const Pkg = struct { | ||
| 815 | name: []const u8, | ||
| 816 | path: []const u8, | ||
| 817 | }; | ||
| 818 | |||
| 810 | pub const LibExeObjStep = struct { | 819 | pub const LibExeObjStep = struct { |
| 811 | step: Step, | 820 | step: Step, |
| 812 | builder: *Builder, | 821 | builder: *Builder, |
| ... | @@ -849,11 +858,6 @@ pub const LibExeObjStep = struct { | ... | @@ -849,11 +858,6 @@ pub const LibExeObjStep = struct { |
| 849 | source_files: ArrayList([]const u8), | 858 | source_files: ArrayList([]const u8), |
| 850 | object_src: []const u8, | 859 | object_src: []const u8, |
| 851 | 860 | ||
| 852 | const Pkg = struct { | ||
| 853 | name: []const u8, | ||
| 854 | path: []const u8, | ||
| 855 | }; | ||
| 856 | |||
| 857 | const Kind = enum { | 861 | const Kind = enum { |
| 858 | Exe, | 862 | Exe, |
| 859 | Lib, | 863 | Lib, |
| ... | @@ -891,8 +895,8 @@ pub const LibExeObjStep = struct { | ... | @@ -891,8 +895,8 @@ pub const LibExeObjStep = struct { |
| 891 | return self; | 895 | return self; |
| 892 | } | 896 | } |
| 893 | 897 | ||
| 894 | pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep { | 898 | pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep { |
| 895 | const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0))) catch unreachable; | 899 | const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0))) catch unreachable; |
| 896 | return self; | 900 | return self; |
| 897 | } | 901 | } |
| 898 | 902 | ||
| ... | @@ -1270,6 +1274,9 @@ pub const LibExeObjStep = struct { | ... | @@ -1270,6 +1274,9 @@ pub const LibExeObjStep = struct { |
| 1270 | zig_args.append("--ver-patch") catch unreachable; | 1274 | zig_args.append("--ver-patch") catch unreachable; |
| 1271 | zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable; | 1275 | zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable; |
| 1272 | } | 1276 | } |
| 1277 | if (self.kind == Kind.Exe and self.static) { | ||
| 1278 | zig_args.append("--static") catch unreachable; | ||
| 1279 | } | ||
| 1273 | 1280 | ||
| 1274 | switch (self.target) { | 1281 | switch (self.target) { |
| 1275 | Target.Native => {}, | 1282 | Target.Native => {}, |
| ... | @@ -1660,6 +1667,7 @@ pub const TestStep = struct { | ... | @@ -1660,6 +1667,7 @@ pub const TestStep = struct { |
| 1660 | exec_cmd_args: ?[]const ?[]const u8, | 1667 | exec_cmd_args: ?[]const ?[]const u8, |
| 1661 | include_dirs: ArrayList([]const u8), | 1668 | include_dirs: ArrayList([]const u8), |
| 1662 | lib_paths: ArrayList([]const u8), | 1669 | lib_paths: ArrayList([]const u8), |
| 1670 | packages: ArrayList(Pkg), | ||
| 1663 | object_files: ArrayList([]const u8), | 1671 | object_files: ArrayList([]const u8), |
| 1664 | no_rosegment: bool, | 1672 | no_rosegment: bool, |
| 1665 | output_path: ?[]const u8, | 1673 | output_path: ?[]const u8, |
| ... | @@ -1680,6 +1688,7 @@ pub const TestStep = struct { | ... | @@ -1680,6 +1688,7 @@ pub const TestStep = struct { |
| 1680 | .exec_cmd_args = null, | 1688 | .exec_cmd_args = null, |
| 1681 | .include_dirs = ArrayList([]const u8).init(builder.allocator), | 1689 | .include_dirs = ArrayList([]const u8).init(builder.allocator), |
| 1682 | .lib_paths = ArrayList([]const u8).init(builder.allocator), | 1690 | .lib_paths = ArrayList([]const u8).init(builder.allocator), |
| 1691 | .packages = ArrayList(Pkg).init(builder.allocator), | ||
| 1683 | .object_files = ArrayList([]const u8).init(builder.allocator), | 1692 | .object_files = ArrayList([]const u8).init(builder.allocator), |
| 1684 | .no_rosegment = false, | 1693 | .no_rosegment = false, |
| 1685 | .output_path = null, | 1694 | .output_path = null, |
| ... | @@ -1695,6 +1704,13 @@ pub const TestStep = struct { | ... | @@ -1695,6 +1704,13 @@ pub const TestStep = struct { |
| 1695 | self.lib_paths.append(path) catch unreachable; | 1704 | self.lib_paths.append(path) catch unreachable; |
| 1696 | } | 1705 | } |
| 1697 | 1706 | ||
| 1707 | pub fn addPackagePath(self: *TestStep, name: []const u8, pkg_index_path: []const u8) void { | ||
| 1708 | self.packages.append(Pkg{ | ||
| 1709 | .name = name, | ||
| 1710 | .path = pkg_index_path, | ||
| 1711 | }) catch unreachable; | ||
| 1712 | } | ||
| 1713 | |||
| 1698 | pub fn setVerbose(self: *TestStep, value: bool) void { | 1714 | pub fn setVerbose(self: *TestStep, value: bool) void { |
| 1699 | self.verbose = value; | 1715 | self.verbose = value; |
| 1700 | } | 1716 | } |
| ... | @@ -1871,6 +1887,13 @@ pub const TestStep = struct { | ... | @@ -1871,6 +1887,13 @@ pub const TestStep = struct { |
| 1871 | try zig_args.append(lib_path); | 1887 | try zig_args.append(lib_path); |
| 1872 | } | 1888 | } |
| 1873 | 1889 | ||
| 1890 | for (self.packages.toSliceConst()) |pkg| { | ||
| 1891 | zig_args.append("--pkg-begin") catch unreachable; | ||
| 1892 | zig_args.append(pkg.name) catch unreachable; | ||
| 1893 | zig_args.append(builder.pathFromRoot(pkg.path)) catch unreachable; | ||
| 1894 | zig_args.append("--pkg-end") catch unreachable; | ||
| 1895 | } | ||
| 1896 | |||
| 1874 | if (self.no_rosegment) { | 1897 | if (self.no_rosegment) { |
| 1875 | try zig_args.append("--no-rosegment"); | 1898 | try zig_args.append("--no-rosegment"); |
| 1876 | } | 1899 | } |
std/debug/index.zig+235-216| ... | @@ -198,49 +198,44 @@ pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, | ... | @@ -198,49 +198,44 @@ pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var, |
| 198 | } | 198 | } |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | pub inline fn getReturnAddress(frame_count: usize) usize { | 201 | pub const StackIterator = struct { |
| 202 | var fp = @ptrToInt(@frameAddress()); | 202 | first_addr: ?usize, |
| 203 | var i: usize = 0; | 203 | fp: usize, |
| 204 | while (fp != 0 and i < frame_count) { | 204 | |
| 205 | fp = @intToPtr(*const usize, fp).*; | 205 | pub fn init(first_addr: ?usize) StackIterator { |
| 206 | i += 1; | 206 | return StackIterator{ |
| 207 | .first_addr = first_addr, | ||
| 208 | .fp = @ptrToInt(@frameAddress()), | ||
| 209 | }; | ||
| 207 | } | 210 | } |
| 208 | return @intToPtr(*const usize, fp + @sizeOf(usize)).*; | 211 | |
| 209 | } | 212 | fn next(self: *StackIterator) ?usize { |
| 213 | if (self.fp == 0) return null; | ||
| 214 | self.fp = @intToPtr(*const usize, self.fp).*; | ||
| 215 | if (self.fp == 0) return null; | ||
| 216 | |||
| 217 | if (self.first_addr) |addr| { | ||
| 218 | while (self.fp != 0) : (self.fp = @intToPtr(*const usize, self.fp).*) { | ||
| 219 | const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*; | ||
| 220 | if (addr == return_address) { | ||
| 221 | self.first_addr = null; | ||
| 222 | return return_address; | ||
| 223 | } | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*; | ||
| 228 | return return_address; | ||
| 229 | } | ||
| 230 | }; | ||
| 210 | 231 | ||
| 211 | pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { | 232 | pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void { |
| 212 | switch (builtin.os) { | 233 | switch (builtin.os) { |
| 213 | builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr), | 234 | builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr), |
| 214 | else => {}, | 235 | else => {}, |
| 215 | } | 236 | } |
| 216 | const AddressState = union(enum) { | 237 | var it = StackIterator.init(start_addr); |
| 217 | NotLookingForStartAddress, | 238 | while (it.next()) |return_address| { |
| 218 | LookingForStartAddress: usize, | ||
| 219 | }; | ||
| 220 | // TODO: I want to express like this: | ||
| 221 | //var addr_state = if (start_addr) |addr| AddressState { .LookingForStartAddress = addr } | ||
| 222 | // else AddressState.NotLookingForStartAddress; | ||
| 223 | var addr_state: AddressState = undefined; | ||
| 224 | if (start_addr) |addr| { | ||
| 225 | addr_state = AddressState{ .LookingForStartAddress = addr }; | ||
| 226 | } else { | ||
| 227 | addr_state = AddressState.NotLookingForStartAddress; | ||
| 228 | } | ||
| 229 | |||
| 230 | var fp = @ptrToInt(@frameAddress()); | ||
| 231 | while (fp != 0) : (fp = @intToPtr(*const usize, fp).*) { | ||
| 232 | const return_address = @intToPtr(*const usize, fp + @sizeOf(usize)).*; | ||
| 233 | |||
| 234 | switch (addr_state) { | ||
| 235 | AddressState.NotLookingForStartAddress => {}, | ||
| 236 | AddressState.LookingForStartAddress => |addr| { | ||
| 237 | if (return_address == addr) { | ||
| 238 | addr_state = AddressState.NotLookingForStartAddress; | ||
| 239 | } else { | ||
| 240 | continue; | ||
| 241 | } | ||
| 242 | }, | ||
| 243 | } | ||
| 244 | try printSourceAtAddress(debug_info, out_stream, return_address, tty_color); | 239 | try printSourceAtAddress(debug_info, out_stream, return_address, tty_color); |
| 245 | } | 240 | } |
| 246 | } | 241 | } |
| ... | @@ -284,7 +279,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres | ... | @@ -284,7 +279,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres |
| 284 | const mod_index = for (di.sect_contribs) |sect_contrib| { | 279 | const mod_index = for (di.sect_contribs) |sect_contrib| { |
| 285 | if (sect_contrib.Section > di.coff.sections.len) continue; | 280 | if (sect_contrib.Section > di.coff.sections.len) continue; |
| 286 | // Remember that SectionContribEntry.Section is 1-based. | 281 | // Remember that SectionContribEntry.Section is 1-based. |
| 287 | coff_section = &di.coff.sections.toSlice()[sect_contrib.Section-1]; | 282 | coff_section = &di.coff.sections.toSlice()[sect_contrib.Section - 1]; |
| 288 | 283 | ||
| 289 | const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset; | 284 | const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset; |
| 290 | const vaddr_end = vaddr_start + sect_contrib.Size; | 285 | const vaddr_end = vaddr_start + sect_contrib.Size; |
| ... | @@ -414,7 +409,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres | ... | @@ -414,7 +409,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres |
| 414 | 409 | ||
| 415 | if (opt_line_info) |line_info| { | 410 | if (opt_line_info) |line_info| { |
| 416 | try out_stream.print("\n"); | 411 | try out_stream.print("\n"); |
| 417 | if (printLineFromFile(out_stream, line_info)) { | 412 | if (printLineFromFileAnyOs(out_stream, line_info)) { |
| 418 | if (line_info.column == 0) { | 413 | if (line_info.column == 0) { |
| 419 | try out_stream.write("\n"); | 414 | try out_stream.write("\n"); |
| 420 | } else { | 415 | } else { |
| ... | @@ -598,7 +593,15 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt | ... | @@ -598,7 +593,15 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt |
| 598 | } else "???"; | 593 | } else "???"; |
| 599 | if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| { | 594 | if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| { |
| 600 | defer line_info.deinit(); | 595 | defer line_info.deinit(); |
| 601 | try printLineInfo(di, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color); | 596 | try printLineInfo( |
| 597 | out_stream, | ||
| 598 | line_info, | ||
| 599 | address, | ||
| 600 | symbol_name, | ||
| 601 | compile_unit_name, | ||
| 602 | tty_color, | ||
| 603 | printLineFromFileAnyOs, | ||
| 604 | ); | ||
| 602 | } else |err| switch (err) { | 605 | } else |err| switch (err) { |
| 603 | error.MissingDebugInfo, error.InvalidDebugInfo => { | 606 | error.MissingDebugInfo, error.InvalidDebugInfo => { |
| 604 | if (tty_color) { | 607 | if (tty_color) { |
| ... | @@ -611,7 +614,15 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt | ... | @@ -611,7 +614,15 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt |
| 611 | } | 614 | } |
| 612 | } | 615 | } |
| 613 | 616 | ||
| 614 | pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { | 617 | /// This function works in freestanding mode. |
| 618 | /// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void | ||
| 619 | pub fn printSourceAtAddressDwarf( | ||
| 620 | debug_info: *DwarfInfo, | ||
| 621 | out_stream: var, | ||
| 622 | address: usize, | ||
| 623 | tty_color: bool, | ||
| 624 | comptime printLineFromFile: var, | ||
| 625 | ) !void { | ||
| 615 | const compile_unit = findCompileUnit(debug_info, address) catch { | 626 | const compile_unit = findCompileUnit(debug_info, address) catch { |
| 616 | if (tty_color) { | 627 | if (tty_color) { |
| 617 | try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address); | 628 | try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address); |
| ... | @@ -621,10 +632,18 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres | ... | @@ -621,10 +632,18 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres |
| 621 | return; | 632 | return; |
| 622 | }; | 633 | }; |
| 623 | const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name); | 634 | const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name); |
| 624 | if (getLineNumberInfoLinux(debug_info, compile_unit, address - 1)) |line_info| { | 635 | if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| { |
| 625 | defer line_info.deinit(); | 636 | defer line_info.deinit(); |
| 626 | const symbol_name = "???"; | 637 | const symbol_name = "???"; |
| 627 | try printLineInfo(debug_info, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color); | 638 | try printLineInfo( |
| 639 | out_stream, | ||
| 640 | line_info, | ||
| 641 | address, | ||
| 642 | symbol_name, | ||
| 643 | compile_unit_name, | ||
| 644 | tty_color, | ||
| 645 | printLineFromFile, | ||
| 646 | ); | ||
| 628 | } else |err| switch (err) { | 647 | } else |err| switch (err) { |
| 629 | error.MissingDebugInfo, error.InvalidDebugInfo => { | 648 | error.MissingDebugInfo, error.InvalidDebugInfo => { |
| 630 | if (tty_color) { | 649 | if (tty_color) { |
| ... | @@ -637,14 +656,18 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres | ... | @@ -637,14 +656,18 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres |
| 637 | } | 656 | } |
| 638 | } | 657 | } |
| 639 | 658 | ||
| 659 | pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void { | ||
| 660 | return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs); | ||
| 661 | } | ||
| 662 | |||
| 640 | fn printLineInfo( | 663 | fn printLineInfo( |
| 641 | debug_info: *DebugInfo, | ||
| 642 | out_stream: var, | 664 | out_stream: var, |
| 643 | line_info: LineInfo, | 665 | line_info: LineInfo, |
| 644 | address: usize, | 666 | address: usize, |
| 645 | symbol_name: []const u8, | 667 | symbol_name: []const u8, |
| 646 | compile_unit_name: []const u8, | 668 | compile_unit_name: []const u8, |
| 647 | tty_color: bool, | 669 | tty_color: bool, |
| 670 | comptime printLineFromFile: var, | ||
| 648 | ) !void { | 671 | ) !void { |
| 649 | if (tty_color) { | 672 | if (tty_color) { |
| 650 | try out_stream.print( | 673 | try out_stream.print( |
| ... | @@ -872,55 +895,68 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize { | ... | @@ -872,55 +895,68 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize { |
| 872 | return list.toOwnedSlice(); | 895 | return list.toOwnedSlice(); |
| 873 | } | 896 | } |
| 874 | 897 | ||
| 875 | fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo { | 898 | fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section { |
| 876 | var di = DebugInfo{ | 899 | const elf_header = (try elf_file.findSection(name)) orelse return null; |
| 877 | .self_exe_file = undefined, | 900 | return DwarfInfo.Section{ |
| 878 | .elf = undefined, | 901 | .offset = elf_header.offset, |
| 879 | .debug_info = undefined, | 902 | .size = elf_header.size, |
| 880 | .debug_abbrev = undefined, | ||
| 881 | .debug_str = undefined, | ||
| 882 | .debug_line = undefined, | ||
| 883 | .debug_ranges = null, | ||
| 884 | .abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator), | ||
| 885 | .compile_unit_list = ArrayList(CompileUnit).init(allocator), | ||
| 886 | }; | 903 | }; |
| 887 | di.self_exe_file = try os.openSelfExe(); | ||
| 888 | errdefer di.self_exe_file.close(); | ||
| 889 | |||
| 890 | try di.elf.openFile(allocator, di.self_exe_file); | ||
| 891 | errdefer di.elf.close(); | ||
| 892 | |||
| 893 | di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo; | ||
| 894 | di.debug_abbrev = (try di.elf.findSection(".debug_abbrev")) orelse return error.MissingDebugInfo; | ||
| 895 | di.debug_str = (try di.elf.findSection(".debug_str")) orelse return error.MissingDebugInfo; | ||
| 896 | di.debug_line = (try di.elf.findSection(".debug_line")) orelse return error.MissingDebugInfo; | ||
| 897 | di.debug_ranges = (try di.elf.findSection(".debug_ranges")); | ||
| 898 | try scanAllCompileUnits(&di); | ||
| 899 | return di; | ||
| 900 | } | 904 | } |
| 901 | 905 | ||
| 902 | pub fn findElfSection(elf: *Elf, name: []const u8) ?*elf.Shdr { | 906 | /// Initialize DWARF info. The caller has the responsibility to initialize most |
| 903 | var file_stream = elf.in_file.inStream(); | 907 | /// the DwarfInfo fields before calling. These fields can be left undefined: |
| 904 | const in = &file_stream.stream; | 908 | /// * abbrev_table_list |
| 905 | 909 | /// * compile_unit_list | |
| 906 | section_loop: for (elf.section_headers) |*elf_section| { | 910 | pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void { |
| 907 | if (elf_section.sh_type == SHT_NULL) continue; | 911 | di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator); |
| 908 | 912 | di.compile_unit_list = ArrayList(CompileUnit).init(allocator); | |
| 909 | const name_offset = elf.string_section.offset + elf_section.name; | 913 | try scanAllCompileUnits(di); |
| 910 | try elf.in_file.seekTo(name_offset); | 914 | } |
| 911 | |||
| 912 | for (name) |expected_c| { | ||
| 913 | const target_c = try in.readByte(); | ||
| 914 | if (target_c == 0 or expected_c != target_c) continue :section_loop; | ||
| 915 | } | ||
| 916 | 915 | ||
| 917 | { | 916 | pub fn openElfDebugInfo( |
| 918 | const null_byte = try in.readByte(); | 917 | allocator: *mem.Allocator, |
| 919 | if (null_byte == 0) return elf_section; | 918 | elf_seekable_stream: *DwarfSeekableStream, |
| 920 | } | 919 | elf_in_stream: *DwarfInStream, |
| 921 | } | 920 | ) !DwarfInfo { |
| 921 | var efile: elf.Elf = undefined; | ||
| 922 | try efile.openStream(allocator, elf_seekable_stream, elf_in_stream); | ||
| 923 | errdefer efile.close(); | ||
| 924 | |||
| 925 | var di = DwarfInfo{ | ||
| 926 | .dwarf_seekable_stream = elf_seekable_stream, | ||
| 927 | .dwarf_in_stream = elf_in_stream, | ||
| 928 | .endian = efile.endian, | ||
| 929 | .debug_info = (try findDwarfSectionFromElf(&efile, ".debug_info")) orelse return error.MissingDebugInfo, | ||
| 930 | .debug_abbrev = (try findDwarfSectionFromElf(&efile, ".debug_abbrev")) orelse return error.MissingDebugInfo, | ||
| 931 | .debug_str = (try findDwarfSectionFromElf(&efile, ".debug_str")) orelse return error.MissingDebugInfo, | ||
| 932 | .debug_line = (try findDwarfSectionFromElf(&efile, ".debug_line")) orelse return error.MissingDebugInfo, | ||
| 933 | .debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")), | ||
| 934 | .abbrev_table_list = undefined, | ||
| 935 | .compile_unit_list = undefined, | ||
| 936 | }; | ||
| 937 | try openDwarfDebugInfo(&di, allocator); | ||
| 938 | return di; | ||
| 939 | } | ||
| 922 | 940 | ||
| 923 | return null; | 941 | fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo { |
| 942 | const S = struct { | ||
| 943 | var self_exe_file: os.File = undefined; | ||
| 944 | var self_exe_seekable_stream: os.File.SeekableStream = undefined; | ||
| 945 | var self_exe_in_stream: os.File.InStream = undefined; | ||
| 946 | }; | ||
| 947 | S.self_exe_file = try os.openSelfExe(); | ||
| 948 | errdefer S.self_exe_file.close(); | ||
| 949 | |||
| 950 | S.self_exe_seekable_stream = S.self_exe_file.seekableStream(); | ||
| 951 | S.self_exe_in_stream = S.self_exe_file.inStream(); | ||
| 952 | |||
| 953 | return openElfDebugInfo( | ||
| 954 | allocator, | ||
| 955 | // TODO https://github.com/ziglang/zig/issues/764 | ||
| 956 | @ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream), | ||
| 957 | // TODO https://github.com/ziglang/zig/issues/764 | ||
| 958 | @ptrCast(*DwarfInStream, &S.self_exe_in_stream.stream), | ||
| 959 | ); | ||
| 924 | } | 960 | } |
| 925 | 961 | ||
| 926 | fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { | 962 | fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { |
| ... | @@ -1000,7 +1036,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { | ... | @@ -1000,7 +1036,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo { |
| 1000 | }; | 1036 | }; |
| 1001 | } | 1037 | } |
| 1002 | 1038 | ||
| 1003 | fn printLineFromFile(out_stream: var, line_info: LineInfo) !void { | 1039 | fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void { |
| 1004 | var f = try os.File.openRead(line_info.file_name); | 1040 | var f = try os.File.openRead(line_info.file_name); |
| 1005 | defer f.close(); | 1041 | defer f.close(); |
| 1006 | // TODO fstat and make sure that the file has the correct size | 1042 | // TODO fstat and make sure that the file has the correct size |
| ... | @@ -1053,6 +1089,35 @@ const MachOFile = struct { | ... | @@ -1053,6 +1089,35 @@ const MachOFile = struct { |
| 1053 | sect_debug_line: ?*const macho.section_64, | 1089 | sect_debug_line: ?*const macho.section_64, |
| 1054 | }; | 1090 | }; |
| 1055 | 1091 | ||
| 1092 | pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror); | ||
| 1093 | pub const DwarfInStream = io.InStream(anyerror); | ||
| 1094 | |||
| 1095 | pub const DwarfInfo = struct { | ||
| 1096 | dwarf_seekable_stream: *DwarfSeekableStream, | ||
| 1097 | dwarf_in_stream: *DwarfInStream, | ||
| 1098 | endian: builtin.Endian, | ||
| 1099 | debug_info: Section, | ||
| 1100 | debug_abbrev: Section, | ||
| 1101 | debug_str: Section, | ||
| 1102 | debug_line: Section, | ||
| 1103 | debug_ranges: ?Section, | ||
| 1104 | abbrev_table_list: ArrayList(AbbrevTableHeader), | ||
| 1105 | compile_unit_list: ArrayList(CompileUnit), | ||
| 1106 | |||
| 1107 | pub const Section = struct { | ||
| 1108 | offset: usize, | ||
| 1109 | size: usize, | ||
| 1110 | }; | ||
| 1111 | |||
| 1112 | pub fn allocator(self: DwarfInfo) *mem.Allocator { | ||
| 1113 | return self.abbrev_table_list.allocator; | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | pub fn readString(self: *DwarfInfo) ![]u8 { | ||
| 1117 | return readStringRaw(self.allocator(), self.dwarf_in_stream); | ||
| 1118 | } | ||
| 1119 | }; | ||
| 1120 | |||
| 1056 | pub const DebugInfo = switch (builtin.os) { | 1121 | pub const DebugInfo = switch (builtin.os) { |
| 1057 | builtin.Os.macosx => struct { | 1122 | builtin.Os.macosx => struct { |
| 1058 | symbols: []const MachoSymbol, | 1123 | symbols: []const MachoSymbol, |
| ... | @@ -1076,32 +1141,7 @@ pub const DebugInfo = switch (builtin.os) { | ... | @@ -1076,32 +1141,7 @@ pub const DebugInfo = switch (builtin.os) { |
| 1076 | sect_contribs: []pdb.SectionContribEntry, | 1141 | sect_contribs: []pdb.SectionContribEntry, |
| 1077 | modules: []Module, | 1142 | modules: []Module, |
| 1078 | }, | 1143 | }, |
| 1079 | builtin.Os.linux => struct { | 1144 | builtin.Os.linux => DwarfInfo, |
| 1080 | self_exe_file: os.File, | ||
| 1081 | elf: elf.Elf, | ||
| 1082 | debug_info: *elf.SectionHeader, | ||
| 1083 | debug_abbrev: *elf.SectionHeader, | ||
| 1084 | debug_str: *elf.SectionHeader, | ||
| 1085 | debug_line: *elf.SectionHeader, | ||
| 1086 | debug_ranges: ?*elf.SectionHeader, | ||
| 1087 | abbrev_table_list: ArrayList(AbbrevTableHeader), | ||
| 1088 | compile_unit_list: ArrayList(CompileUnit), | ||
| 1089 | |||
| 1090 | pub fn allocator(self: DebugInfo) *mem.Allocator { | ||
| 1091 | return self.abbrev_table_list.allocator; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | pub fn readString(self: *DebugInfo) ![]u8 { | ||
| 1095 | var in_file_stream = self.self_exe_file.inStream(); | ||
| 1096 | const in_stream = &in_file_stream.stream; | ||
| 1097 | return readStringRaw(self.allocator(), in_stream); | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | pub fn close(self: *DebugInfo) void { | ||
| 1101 | self.self_exe_file.close(); | ||
| 1102 | self.elf.close(); | ||
| 1103 | } | ||
| 1104 | }, | ||
| 1105 | builtin.Os.freebsd => struct {}, | 1145 | builtin.Os.freebsd => struct {}, |
| 1106 | else => @compileError("Unsupported OS"), | 1146 | else => @compileError("Unsupported OS"), |
| 1107 | }; | 1147 | }; |
| ... | @@ -1206,11 +1246,11 @@ const Die = struct { | ... | @@ -1206,11 +1246,11 @@ const Die = struct { |
| 1206 | }; | 1246 | }; |
| 1207 | } | 1247 | } |
| 1208 | 1248 | ||
| 1209 | fn getAttrString(self: *const Die, st: *DebugInfo, id: u64) ![]u8 { | 1249 | fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 { |
| 1210 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; | 1250 | const form_value = self.getAttr(id) orelse return error.MissingDebugInfo; |
| 1211 | return switch (form_value.*) { | 1251 | return switch (form_value.*) { |
| 1212 | FormValue.String => |value| value, | 1252 | FormValue.String => |value| value, |
| 1213 | FormValue.StrPtr => |offset| getString(st, offset), | 1253 | FormValue.StrPtr => |offset| getString(di, offset), |
| 1214 | else => error.InvalidDebugInfo, | 1254 | else => error.InvalidDebugInfo, |
| 1215 | }; | 1255 | }; |
| 1216 | } | 1256 | } |
| ... | @@ -1223,14 +1263,15 @@ const FileEntry = struct { | ... | @@ -1223,14 +1263,15 @@ const FileEntry = struct { |
| 1223 | len_bytes: usize, | 1263 | len_bytes: usize, |
| 1224 | }; | 1264 | }; |
| 1225 | 1265 | ||
| 1226 | const LineInfo = struct { | 1266 | pub const LineInfo = struct { |
| 1227 | line: usize, | 1267 | line: usize, |
| 1228 | column: usize, | 1268 | column: usize, |
| 1229 | file_name: []u8, | 1269 | file_name: []const u8, |
| 1230 | allocator: *mem.Allocator, | 1270 | allocator: ?*mem.Allocator, |
| 1231 | 1271 | ||
| 1232 | fn deinit(self: *const LineInfo) void { | 1272 | fn deinit(self: LineInfo) void { |
| 1233 | self.allocator.free(self.file_name); | 1273 | const allocator = self.allocator orelse return; |
| 1274 | allocator.free(self.file_name); | ||
| 1234 | } | 1275 | } |
| 1235 | }; | 1276 | }; |
| 1236 | 1277 | ||
| ... | @@ -1321,10 +1362,10 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 { | ... | @@ -1321,10 +1362,10 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 { |
| 1321 | return buf.toSlice(); | 1362 | return buf.toSlice(); |
| 1322 | } | 1363 | } |
| 1323 | 1364 | ||
| 1324 | fn getString(st: *DebugInfo, offset: u64) ![]u8 { | 1365 | fn getString(di: *DwarfInfo, offset: u64) ![]u8 { |
| 1325 | const pos = st.debug_str.offset + offset; | 1366 | const pos = di.debug_str.offset + offset; |
| 1326 | try st.self_exe_file.seekTo(pos); | 1367 | try di.dwarf_seekable_stream.seekTo(pos); |
| 1327 | return st.readString(); | 1368 | return di.readString(); |
| 1328 | } | 1369 | } |
| 1329 | 1370 | ||
| 1330 | fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 { | 1371 | fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 { |
| ... | @@ -1371,14 +1412,7 @@ fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type | ... | @@ -1371,14 +1412,7 @@ fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type |
| 1371 | return parseFormValueRefLen(allocator, in_stream, block_len); | 1412 | return parseFormValueRefLen(allocator, in_stream, block_len); |
| 1372 | } | 1413 | } |
| 1373 | 1414 | ||
| 1374 | const ParseFormValueError = error{ | 1415 | fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue { |
| 1375 | EndOfStream, | ||
| 1376 | InvalidDebugInfo, | ||
| 1377 | EndOfFile, | ||
| 1378 | OutOfMemory, | ||
| 1379 | } || std.os.File.ReadError; | ||
| 1380 | |||
| 1381 | fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) ParseFormValueError!FormValue { | ||
| 1382 | return switch (form_id) { | 1416 | return switch (form_id) { |
| 1383 | DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) }, | 1417 | DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) }, |
| 1384 | DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1), | 1418 | DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1), |
| ... | @@ -1428,25 +1462,22 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 | ... | @@ -1428,25 +1462,22 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64 |
| 1428 | }; | 1462 | }; |
| 1429 | } | 1463 | } |
| 1430 | 1464 | ||
| 1431 | fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable { | 1465 | fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable { |
| 1432 | const in_file = st.self_exe_file; | 1466 | var result = AbbrevTable.init(di.allocator()); |
| 1433 | var in_file_stream = in_file.inStream(); | ||
| 1434 | const in_stream = &in_file_stream.stream; | ||
| 1435 | var result = AbbrevTable.init(st.allocator()); | ||
| 1436 | while (true) { | 1467 | while (true) { |
| 1437 | const abbrev_code = try readULeb128(in_stream); | 1468 | const abbrev_code = try readULeb128(di.dwarf_in_stream); |
| 1438 | if (abbrev_code == 0) return result; | 1469 | if (abbrev_code == 0) return result; |
| 1439 | try result.append(AbbrevTableEntry{ | 1470 | try result.append(AbbrevTableEntry{ |
| 1440 | .abbrev_code = abbrev_code, | 1471 | .abbrev_code = abbrev_code, |
| 1441 | .tag_id = try readULeb128(in_stream), | 1472 | .tag_id = try readULeb128(di.dwarf_in_stream), |
| 1442 | .has_children = (try in_stream.readByte()) == DW.CHILDREN_yes, | 1473 | .has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes, |
| 1443 | .attrs = ArrayList(AbbrevAttr).init(st.allocator()), | 1474 | .attrs = ArrayList(AbbrevAttr).init(di.allocator()), |
| 1444 | }); | 1475 | }); |
| 1445 | const attrs = &result.items[result.len - 1].attrs; | 1476 | const attrs = &result.items[result.len - 1].attrs; |
| 1446 | 1477 | ||
| 1447 | while (true) { | 1478 | while (true) { |
| 1448 | const attr_id = try readULeb128(in_stream); | 1479 | const attr_id = try readULeb128(di.dwarf_in_stream); |
| 1449 | const form_id = try readULeb128(in_stream); | 1480 | const form_id = try readULeb128(di.dwarf_in_stream); |
| 1450 | if (attr_id == 0 and form_id == 0) break; | 1481 | if (attr_id == 0 and form_id == 0) break; |
| 1451 | try attrs.append(AbbrevAttr{ | 1482 | try attrs.append(AbbrevAttr{ |
| 1452 | .attr_id = attr_id, | 1483 | .attr_id = attr_id, |
| ... | @@ -1458,18 +1489,18 @@ fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable { | ... | @@ -1458,18 +1489,18 @@ fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable { |
| 1458 | 1489 | ||
| 1459 | /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, | 1490 | /// Gets an already existing AbbrevTable given the abbrev_offset, or if not found, |
| 1460 | /// seeks in the stream and parses it. | 1491 | /// seeks in the stream and parses it. |
| 1461 | fn getAbbrevTable(st: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable { | 1492 | fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable { |
| 1462 | for (st.abbrev_table_list.toSlice()) |*header| { | 1493 | for (di.abbrev_table_list.toSlice()) |*header| { |
| 1463 | if (header.offset == abbrev_offset) { | 1494 | if (header.offset == abbrev_offset) { |
| 1464 | return &header.table; | 1495 | return &header.table; |
| 1465 | } | 1496 | } |
| 1466 | } | 1497 | } |
| 1467 | try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset); | 1498 | try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset); |
| 1468 | try st.abbrev_table_list.append(AbbrevTableHeader{ | 1499 | try di.abbrev_table_list.append(AbbrevTableHeader{ |
| 1469 | .offset = abbrev_offset, | 1500 | .offset = abbrev_offset, |
| 1470 | .table = try parseAbbrevTable(st), | 1501 | .table = try parseAbbrevTable(di), |
| 1471 | }); | 1502 | }); |
| 1472 | return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table; | 1503 | return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table; |
| 1473 | } | 1504 | } |
| 1474 | 1505 | ||
| 1475 | fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry { | 1506 | fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry { |
| ... | @@ -1479,23 +1510,20 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con | ... | @@ -1479,23 +1510,20 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con |
| 1479 | return null; | 1510 | return null; |
| 1480 | } | 1511 | } |
| 1481 | 1512 | ||
| 1482 | fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { | 1513 | fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die { |
| 1483 | const in_file = st.self_exe_file; | 1514 | const abbrev_code = try readULeb128(di.dwarf_in_stream); |
| 1484 | var in_file_stream = in_file.inStream(); | ||
| 1485 | const in_stream = &in_file_stream.stream; | ||
| 1486 | const abbrev_code = try readULeb128(in_stream); | ||
| 1487 | const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; | 1515 | const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo; |
| 1488 | 1516 | ||
| 1489 | var result = Die{ | 1517 | var result = Die{ |
| 1490 | .tag_id = table_entry.tag_id, | 1518 | .tag_id = table_entry.tag_id, |
| 1491 | .has_children = table_entry.has_children, | 1519 | .has_children = table_entry.has_children, |
| 1492 | .attrs = ArrayList(Die.Attr).init(st.allocator()), | 1520 | .attrs = ArrayList(Die.Attr).init(di.allocator()), |
| 1493 | }; | 1521 | }; |
| 1494 | try result.attrs.resize(table_entry.attrs.len); | 1522 | try result.attrs.resize(table_entry.attrs.len); |
| 1495 | for (table_entry.attrs.toSliceConst()) |attr, i| { | 1523 | for (table_entry.attrs.toSliceConst()) |attr, i| { |
| 1496 | result.attrs.items[i] = Die.Attr{ | 1524 | result.attrs.items[i] = Die.Attr{ |
| 1497 | .id = attr.attr_id, | 1525 | .id = attr.attr_id, |
| 1498 | .value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64), | 1526 | .value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64), |
| 1499 | }; | 1527 | }; |
| 1500 | } | 1528 | } |
| 1501 | return result; | 1529 | return result; |
| ... | @@ -1699,22 +1727,18 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u | ... | @@ -1699,22 +1727,18 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u |
| 1699 | return error.MissingDebugInfo; | 1727 | return error.MissingDebugInfo; |
| 1700 | } | 1728 | } |
| 1701 | 1729 | ||
| 1702 | fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo { | 1730 | fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo { |
| 1703 | const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir); | 1731 | const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir); |
| 1704 | 1732 | ||
| 1705 | const in_file = di.self_exe_file; | ||
| 1706 | const debug_line_end = di.debug_line.offset + di.debug_line.size; | 1733 | const debug_line_end = di.debug_line.offset + di.debug_line.size; |
| 1707 | var this_offset = di.debug_line.offset; | 1734 | var this_offset = di.debug_line.offset; |
| 1708 | var this_index: usize = 0; | 1735 | var this_index: usize = 0; |
| 1709 | 1736 | ||
| 1710 | var in_file_stream = in_file.inStream(); | ||
| 1711 | const in_stream = &in_file_stream.stream; | ||
| 1712 | |||
| 1713 | while (this_offset < debug_line_end) : (this_index += 1) { | 1737 | while (this_offset < debug_line_end) : (this_index += 1) { |
| 1714 | try in_file.seekTo(this_offset); | 1738 | try di.dwarf_seekable_stream.seekTo(this_offset); |
| 1715 | 1739 | ||
| 1716 | var is_64: bool = undefined; | 1740 | var is_64: bool = undefined; |
| 1717 | const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64); | 1741 | const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64); |
| 1718 | if (unit_length == 0) return error.MissingDebugInfo; | 1742 | if (unit_length == 0) return error.MissingDebugInfo; |
| 1719 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); | 1743 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); |
| 1720 | 1744 | ||
| ... | @@ -1723,35 +1747,35 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ | ... | @@ -1723,35 +1747,35 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ |
| 1723 | continue; | 1747 | continue; |
| 1724 | } | 1748 | } |
| 1725 | 1749 | ||
| 1726 | const version = try in_stream.readInt(di.elf.endian, u16); | 1750 | const version = try di.dwarf_in_stream.readInt(di.endian, u16); |
| 1727 | // TODO support 3 and 5 | 1751 | // TODO support 3 and 5 |
| 1728 | if (version != 2 and version != 4) return error.InvalidDebugInfo; | 1752 | if (version != 2 and version != 4) return error.InvalidDebugInfo; |
| 1729 | 1753 | ||
| 1730 | const prologue_length = if (is_64) try in_stream.readInt(di.elf.endian, u64) else try in_stream.readInt(di.elf.endian, u32); | 1754 | const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32); |
| 1731 | const prog_start_offset = (try in_file.getPos()) + prologue_length; | 1755 | const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length; |
| 1732 | 1756 | ||
| 1733 | const minimum_instruction_length = try in_stream.readByte(); | 1757 | const minimum_instruction_length = try di.dwarf_in_stream.readByte(); |
| 1734 | if (minimum_instruction_length == 0) return error.InvalidDebugInfo; | 1758 | if (minimum_instruction_length == 0) return error.InvalidDebugInfo; |
| 1735 | 1759 | ||
| 1736 | if (version >= 4) { | 1760 | if (version >= 4) { |
| 1737 | // maximum_operations_per_instruction | 1761 | // maximum_operations_per_instruction |
| 1738 | _ = try in_stream.readByte(); | 1762 | _ = try di.dwarf_in_stream.readByte(); |
| 1739 | } | 1763 | } |
| 1740 | 1764 | ||
| 1741 | const default_is_stmt = (try in_stream.readByte()) != 0; | 1765 | const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0; |
| 1742 | const line_base = try in_stream.readByteSigned(); | 1766 | const line_base = try di.dwarf_in_stream.readByteSigned(); |
| 1743 | 1767 | ||
| 1744 | const line_range = try in_stream.readByte(); | 1768 | const line_range = try di.dwarf_in_stream.readByte(); |
| 1745 | if (line_range == 0) return error.InvalidDebugInfo; | 1769 | if (line_range == 0) return error.InvalidDebugInfo; |
| 1746 | 1770 | ||
| 1747 | const opcode_base = try in_stream.readByte(); | 1771 | const opcode_base = try di.dwarf_in_stream.readByte(); |
| 1748 | 1772 | ||
| 1749 | const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1); | 1773 | const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1); |
| 1750 | 1774 | ||
| 1751 | { | 1775 | { |
| 1752 | var i: usize = 0; | 1776 | var i: usize = 0; |
| 1753 | while (i < opcode_base - 1) : (i += 1) { | 1777 | while (i < opcode_base - 1) : (i += 1) { |
| 1754 | standard_opcode_lengths[i] = try in_stream.readByte(); | 1778 | standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte(); |
| 1755 | } | 1779 | } |
| 1756 | } | 1780 | } |
| 1757 | 1781 | ||
| ... | @@ -1769,9 +1793,9 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ | ... | @@ -1769,9 +1793,9 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ |
| 1769 | while (true) { | 1793 | while (true) { |
| 1770 | const file_name = try di.readString(); | 1794 | const file_name = try di.readString(); |
| 1771 | if (file_name.len == 0) break; | 1795 | if (file_name.len == 0) break; |
| 1772 | const dir_index = try readULeb128(in_stream); | 1796 | const dir_index = try readULeb128(di.dwarf_in_stream); |
| 1773 | const mtime = try readULeb128(in_stream); | 1797 | const mtime = try readULeb128(di.dwarf_in_stream); |
| 1774 | const len_bytes = try readULeb128(in_stream); | 1798 | const len_bytes = try readULeb128(di.dwarf_in_stream); |
| 1775 | try file_entries.append(FileEntry{ | 1799 | try file_entries.append(FileEntry{ |
| 1776 | .file_name = file_name, | 1800 | .file_name = file_name, |
| 1777 | .dir_index = dir_index, | 1801 | .dir_index = dir_index, |
| ... | @@ -1780,15 +1804,15 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ | ... | @@ -1780,15 +1804,15 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ |
| 1780 | }); | 1804 | }); |
| 1781 | } | 1805 | } |
| 1782 | 1806 | ||
| 1783 | try in_file.seekTo(prog_start_offset); | 1807 | try di.dwarf_seekable_stream.seekTo(prog_start_offset); |
| 1784 | 1808 | ||
| 1785 | while (true) { | 1809 | while (true) { |
| 1786 | const opcode = try in_stream.readByte(); | 1810 | const opcode = try di.dwarf_in_stream.readByte(); |
| 1787 | 1811 | ||
| 1788 | if (opcode == DW.LNS_extended_op) { | 1812 | if (opcode == DW.LNS_extended_op) { |
| 1789 | const op_size = try readULeb128(in_stream); | 1813 | const op_size = try readULeb128(di.dwarf_in_stream); |
| 1790 | if (op_size < 1) return error.InvalidDebugInfo; | 1814 | if (op_size < 1) return error.InvalidDebugInfo; |
| 1791 | var sub_op = try in_stream.readByte(); | 1815 | var sub_op = try di.dwarf_in_stream.readByte(); |
| 1792 | switch (sub_op) { | 1816 | switch (sub_op) { |
| 1793 | DW.LNE_end_sequence => { | 1817 | DW.LNE_end_sequence => { |
| 1794 | prog.end_sequence = true; | 1818 | prog.end_sequence = true; |
| ... | @@ -1796,14 +1820,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ | ... | @@ -1796,14 +1820,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ |
| 1796 | return error.MissingDebugInfo; | 1820 | return error.MissingDebugInfo; |
| 1797 | }, | 1821 | }, |
| 1798 | DW.LNE_set_address => { | 1822 | DW.LNE_set_address => { |
| 1799 | const addr = try in_stream.readInt(di.elf.endian, usize); | 1823 | const addr = try di.dwarf_in_stream.readInt(di.endian, usize); |
| 1800 | prog.address = addr; | 1824 | prog.address = addr; |
| 1801 | }, | 1825 | }, |
| 1802 | DW.LNE_define_file => { | 1826 | DW.LNE_define_file => { |
| 1803 | const file_name = try di.readString(); | 1827 | const file_name = try di.readString(); |
| 1804 | const dir_index = try readULeb128(in_stream); | 1828 | const dir_index = try readULeb128(di.dwarf_in_stream); |
| 1805 | const mtime = try readULeb128(in_stream); | 1829 | const mtime = try readULeb128(di.dwarf_in_stream); |
| 1806 | const len_bytes = try readULeb128(in_stream); | 1830 | const len_bytes = try readULeb128(di.dwarf_in_stream); |
| 1807 | try file_entries.append(FileEntry{ | 1831 | try file_entries.append(FileEntry{ |
| 1808 | .file_name = file_name, | 1832 | .file_name = file_name, |
| 1809 | .dir_index = dir_index, | 1833 | .dir_index = dir_index, |
| ... | @@ -1813,7 +1837,7 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ | ... | @@ -1813,7 +1837,7 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ |
| 1813 | }, | 1837 | }, |
| 1814 | else => { | 1838 | else => { |
| 1815 | const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo; | 1839 | const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo; |
| 1816 | try in_file.seekForward(fwd_amt); | 1840 | try di.dwarf_seekable_stream.seekForward(fwd_amt); |
| 1817 | }, | 1841 | }, |
| 1818 | } | 1842 | } |
| 1819 | } else if (opcode >= opcode_base) { | 1843 | } else if (opcode >= opcode_base) { |
| ... | @@ -1832,19 +1856,19 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ | ... | @@ -1832,19 +1856,19 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ |
| 1832 | prog.basic_block = false; | 1856 | prog.basic_block = false; |
| 1833 | }, | 1857 | }, |
| 1834 | DW.LNS_advance_pc => { | 1858 | DW.LNS_advance_pc => { |
| 1835 | const arg = try readULeb128(in_stream); | 1859 | const arg = try readULeb128(di.dwarf_in_stream); |
| 1836 | prog.address += arg * minimum_instruction_length; | 1860 | prog.address += arg * minimum_instruction_length; |
| 1837 | }, | 1861 | }, |
| 1838 | DW.LNS_advance_line => { | 1862 | DW.LNS_advance_line => { |
| 1839 | const arg = try readILeb128(in_stream); | 1863 | const arg = try readILeb128(di.dwarf_in_stream); |
| 1840 | prog.line += arg; | 1864 | prog.line += arg; |
| 1841 | }, | 1865 | }, |
| 1842 | DW.LNS_set_file => { | 1866 | DW.LNS_set_file => { |
| 1843 | const arg = try readULeb128(in_stream); | 1867 | const arg = try readULeb128(di.dwarf_in_stream); |
| 1844 | prog.file = arg; | 1868 | prog.file = arg; |
| 1845 | }, | 1869 | }, |
| 1846 | DW.LNS_set_column => { | 1870 | DW.LNS_set_column => { |
| 1847 | const arg = try readULeb128(in_stream); | 1871 | const arg = try readULeb128(di.dwarf_in_stream); |
| 1848 | prog.column = arg; | 1872 | prog.column = arg; |
| 1849 | }, | 1873 | }, |
| 1850 | DW.LNS_negate_stmt => { | 1874 | DW.LNS_negate_stmt => { |
| ... | @@ -1858,14 +1882,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ | ... | @@ -1858,14 +1882,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ |
| 1858 | prog.address += inc_addr; | 1882 | prog.address += inc_addr; |
| 1859 | }, | 1883 | }, |
| 1860 | DW.LNS_fixed_advance_pc => { | 1884 | DW.LNS_fixed_advance_pc => { |
| 1861 | const arg = try in_stream.readInt(di.elf.endian, u16); | 1885 | const arg = try di.dwarf_in_stream.readInt(di.endian, u16); |
| 1862 | prog.address += arg; | 1886 | prog.address += arg; |
| 1863 | }, | 1887 | }, |
| 1864 | DW.LNS_set_prologue_end => {}, | 1888 | DW.LNS_set_prologue_end => {}, |
| 1865 | else => { | 1889 | else => { |
| 1866 | if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo; | 1890 | if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo; |
| 1867 | const len_bytes = standard_opcode_lengths[opcode - 1]; | 1891 | const len_bytes = standard_opcode_lengths[opcode - 1]; |
| 1868 | try in_file.seekForward(len_bytes); | 1892 | try di.dwarf_seekable_stream.seekForward(len_bytes); |
| 1869 | }, | 1893 | }, |
| 1870 | } | 1894 | } |
| 1871 | } | 1895 | } |
| ... | @@ -1877,36 +1901,33 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ | ... | @@ -1877,36 +1901,33 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ |
| 1877 | return error.MissingDebugInfo; | 1901 | return error.MissingDebugInfo; |
| 1878 | } | 1902 | } |
| 1879 | 1903 | ||
| 1880 | fn scanAllCompileUnits(st: *DebugInfo) !void { | 1904 | fn scanAllCompileUnits(di: *DwarfInfo) !void { |
| 1881 | const debug_info_end = st.debug_info.offset + st.debug_info.size; | 1905 | const debug_info_end = di.debug_info.offset + di.debug_info.size; |
| 1882 | var this_unit_offset = st.debug_info.offset; | 1906 | var this_unit_offset = di.debug_info.offset; |
| 1883 | var cu_index: usize = 0; | 1907 | var cu_index: usize = 0; |
| 1884 | 1908 | ||
| 1885 | var in_file_stream = st.self_exe_file.inStream(); | ||
| 1886 | const in_stream = &in_file_stream.stream; | ||
| 1887 | |||
| 1888 | while (this_unit_offset < debug_info_end) { | 1909 | while (this_unit_offset < debug_info_end) { |
| 1889 | try st.self_exe_file.seekTo(this_unit_offset); | 1910 | try di.dwarf_seekable_stream.seekTo(this_unit_offset); |
| 1890 | 1911 | ||
| 1891 | var is_64: bool = undefined; | 1912 | var is_64: bool = undefined; |
| 1892 | const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64); | 1913 | const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64); |
| 1893 | if (unit_length == 0) return; | 1914 | if (unit_length == 0) return; |
| 1894 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); | 1915 | const next_offset = unit_length + (if (is_64) usize(12) else usize(4)); |
| 1895 | 1916 | ||
| 1896 | const version = try in_stream.readInt(st.elf.endian, u16); | 1917 | const version = try di.dwarf_in_stream.readInt(di.endian, u16); |
| 1897 | if (version < 2 or version > 5) return error.InvalidDebugInfo; | 1918 | if (version < 2 or version > 5) return error.InvalidDebugInfo; |
| 1898 | 1919 | ||
| 1899 | const debug_abbrev_offset = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32); | 1920 | const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(di.endian, u64) else try di.dwarf_in_stream.readInt(di.endian, u32); |
| 1900 | 1921 | ||
| 1901 | const address_size = try in_stream.readByte(); | 1922 | const address_size = try di.dwarf_in_stream.readByte(); |
| 1902 | if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; | 1923 | if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo; |
| 1903 | 1924 | ||
| 1904 | const compile_unit_pos = try st.self_exe_file.getPos(); | 1925 | const compile_unit_pos = try di.dwarf_seekable_stream.getPos(); |
| 1905 | const abbrev_table = try getAbbrevTable(st, debug_abbrev_offset); | 1926 | const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset); |
| 1906 | 1927 | ||
| 1907 | try st.self_exe_file.seekTo(compile_unit_pos); | 1928 | try di.dwarf_seekable_stream.seekTo(compile_unit_pos); |
| 1908 | 1929 | ||
| 1909 | const compile_unit_die = try st.allocator().create(try parseDie(st, abbrev_table, is_64)); | 1930 | const compile_unit_die = try di.allocator().create(try parseDie(di, abbrev_table, is_64)); |
| 1910 | 1931 | ||
| 1911 | if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo; | 1932 | if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo; |
| 1912 | 1933 | ||
| ... | @@ -1934,7 +1955,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void { | ... | @@ -1934,7 +1955,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void { |
| 1934 | } | 1955 | } |
| 1935 | }; | 1956 | }; |
| 1936 | 1957 | ||
| 1937 | try st.compile_unit_list.append(CompileUnit{ | 1958 | try di.compile_unit_list.append(CompileUnit{ |
| 1938 | .version = version, | 1959 | .version = version, |
| 1939 | .is_64 = is_64, | 1960 | .is_64 = is_64, |
| 1940 | .pc_range = pc_range, | 1961 | .pc_range = pc_range, |
| ... | @@ -1947,20 +1968,18 @@ fn scanAllCompileUnits(st: *DebugInfo) !void { | ... | @@ -1947,20 +1968,18 @@ fn scanAllCompileUnits(st: *DebugInfo) !void { |
| 1947 | } | 1968 | } |
| 1948 | } | 1969 | } |
| 1949 | 1970 | ||
| 1950 | fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit { | 1971 | fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit { |
| 1951 | var in_file_stream = st.self_exe_file.inStream(); | 1972 | for (di.compile_unit_list.toSlice()) |*compile_unit| { |
| 1952 | const in_stream = &in_file_stream.stream; | ||
| 1953 | for (st.compile_unit_list.toSlice()) |*compile_unit| { | ||
| 1954 | if (compile_unit.pc_range) |range| { | 1973 | if (compile_unit.pc_range) |range| { |
| 1955 | if (target_address >= range.start and target_address < range.end) return compile_unit; | 1974 | if (target_address >= range.start and target_address < range.end) return compile_unit; |
| 1956 | } | 1975 | } |
| 1957 | if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| { | 1976 | if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| { |
| 1958 | var base_address: usize = 0; | 1977 | var base_address: usize = 0; |
| 1959 | if (st.debug_ranges) |debug_ranges| { | 1978 | if (di.debug_ranges) |debug_ranges| { |
| 1960 | try st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset); | 1979 | try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset); |
| 1961 | while (true) { | 1980 | while (true) { |
| 1962 | const begin_addr = try in_stream.readIntLe(usize); | 1981 | const begin_addr = try di.dwarf_in_stream.readIntLe(usize); |
| 1963 | const end_addr = try in_stream.readIntLe(usize); | 1982 | const end_addr = try di.dwarf_in_stream.readIntLe(usize); |
| 1964 | if (begin_addr == 0 and end_addr == 0) { | 1983 | if (begin_addr == 0 and end_addr == 0) { |
| 1965 | break; | 1984 | break; |
| 1966 | } | 1985 | } |
std/elf.zig+24-21| ... | @@ -353,7 +353,8 @@ pub const SectionHeader = struct { | ... | @@ -353,7 +353,8 @@ pub const SectionHeader = struct { |
| 353 | }; | 353 | }; |
| 354 | 354 | ||
| 355 | pub const Elf = struct { | 355 | pub const Elf = struct { |
| 356 | in_file: os.File, | 356 | seekable_stream: *io.SeekableStream(anyerror, anyerror), |
| 357 | in_stream: *io.InStream(anyerror), | ||
| 357 | auto_close_stream: bool, | 358 | auto_close_stream: bool, |
| 358 | is_64: bool, | 359 | is_64: bool, |
| 359 | endian: builtin.Endian, | 360 | endian: builtin.Endian, |
| ... | @@ -370,19 +371,24 @@ pub const Elf = struct { | ... | @@ -370,19 +371,24 @@ pub const Elf = struct { |
| 370 | 371 | ||
| 371 | /// Call close when done. | 372 | /// Call close when done. |
| 372 | pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void { | 373 | pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void { |
| 373 | try elf.prealloc_file.open(path); | 374 | @compileError("TODO implement"); |
| 374 | try elf.openFile(allocator, *elf.prealloc_file); | ||
| 375 | elf.auto_close_stream = true; | ||
| 376 | } | 375 | } |
| 377 | 376 | ||
| 378 | /// Call close when done. | 377 | /// Call close when done. |
| 379 | pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: os.File) !void { | 378 | pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: os.File) !void { |
| 380 | elf.allocator = allocator; | 379 | @compileError("TODO implement"); |
| 381 | elf.in_file = file; | 380 | } |
| 382 | elf.auto_close_stream = false; | ||
| 383 | 381 | ||
| 384 | var file_stream = elf.in_file.inStream(); | 382 | pub fn openStream( |
| 385 | const in = &file_stream.stream; | 383 | elf: *Elf, |
| 384 | allocator: *mem.Allocator, | ||
| 385 | seekable_stream: *io.SeekableStream(anyerror, anyerror), | ||
| 386 | in: *io.InStream(anyerror), | ||
| 387 | ) !void { | ||
| 388 | elf.auto_close_stream = false; | ||
| 389 | elf.allocator = allocator; | ||
| 390 | elf.seekable_stream = seekable_stream; | ||
| 391 | elf.in_stream = in; | ||
| 386 | 392 | ||
| 387 | var magic: [4]u8 = undefined; | 393 | var magic: [4]u8 = undefined; |
| 388 | try in.readNoEof(magic[0..]); | 394 | try in.readNoEof(magic[0..]); |
| ... | @@ -404,7 +410,7 @@ pub const Elf = struct { | ... | @@ -404,7 +410,7 @@ pub const Elf = struct { |
| 404 | if (version_byte != 1) return error.InvalidFormat; | 410 | if (version_byte != 1) return error.InvalidFormat; |
| 405 | 411 | ||
| 406 | // skip over padding | 412 | // skip over padding |
| 407 | try elf.in_file.seekForward(9); | 413 | try seekable_stream.seekForward(9); |
| 408 | 414 | ||
| 409 | elf.file_type = switch (try in.readInt(elf.endian, u16)) { | 415 | elf.file_type = switch (try in.readInt(elf.endian, u16)) { |
| 410 | 1 => FileType.Relocatable, | 416 | 1 => FileType.Relocatable, |
| ... | @@ -441,7 +447,7 @@ pub const Elf = struct { | ... | @@ -441,7 +447,7 @@ pub const Elf = struct { |
| 441 | } | 447 | } |
| 442 | 448 | ||
| 443 | // skip over flags | 449 | // skip over flags |
| 444 | try elf.in_file.seekForward(4); | 450 | try seekable_stream.seekForward(4); |
| 445 | 451 | ||
| 446 | const header_size = try in.readInt(elf.endian, u16); | 452 | const header_size = try in.readInt(elf.endian, u16); |
| 447 | if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) { | 453 | if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) { |
| ... | @@ -461,12 +467,12 @@ pub const Elf = struct { | ... | @@ -461,12 +467,12 @@ pub const Elf = struct { |
| 461 | const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count); | 467 | const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count); |
| 462 | const end_ph = try math.add(u64, elf.program_header_offset, ph_byte_count); | 468 | const end_ph = try math.add(u64, elf.program_header_offset, ph_byte_count); |
| 463 | 469 | ||
| 464 | const stream_end = try elf.in_file.getEndPos(); | 470 | const stream_end = try seekable_stream.getEndPos(); |
| 465 | if (stream_end < end_sh or stream_end < end_ph) { | 471 | if (stream_end < end_sh or stream_end < end_ph) { |
| 466 | return error.InvalidFormat; | 472 | return error.InvalidFormat; |
| 467 | } | 473 | } |
| 468 | 474 | ||
| 469 | try elf.in_file.seekTo(elf.section_header_offset); | 475 | try seekable_stream.seekTo(elf.section_header_offset); |
| 470 | 476 | ||
| 471 | elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count); | 477 | elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count); |
| 472 | errdefer elf.allocator.free(elf.section_headers); | 478 | errdefer elf.allocator.free(elf.section_headers); |
| ... | @@ -521,26 +527,23 @@ pub const Elf = struct { | ... | @@ -521,26 +527,23 @@ pub const Elf = struct { |
| 521 | pub fn close(elf: *Elf) void { | 527 | pub fn close(elf: *Elf) void { |
| 522 | elf.allocator.free(elf.section_headers); | 528 | elf.allocator.free(elf.section_headers); |
| 523 | 529 | ||
| 524 | if (elf.auto_close_stream) elf.in_file.close(); | 530 | if (elf.auto_close_stream) elf.prealloc_file.close(); |
| 525 | } | 531 | } |
| 526 | 532 | ||
| 527 | pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader { | 533 | pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader { |
| 528 | var file_stream = elf.in_file.inStream(); | ||
| 529 | const in = &file_stream.stream; | ||
| 530 | |||
| 531 | section_loop: for (elf.section_headers) |*elf_section| { | 534 | section_loop: for (elf.section_headers) |*elf_section| { |
| 532 | if (elf_section.sh_type == SHT_NULL) continue; | 535 | if (elf_section.sh_type == SHT_NULL) continue; |
| 533 | 536 | ||
| 534 | const name_offset = elf.string_section.offset + elf_section.name; | 537 | const name_offset = elf.string_section.offset + elf_section.name; |
| 535 | try elf.in_file.seekTo(name_offset); | 538 | try elf.seekable_stream.seekTo(name_offset); |
| 536 | 539 | ||
| 537 | for (name) |expected_c| { | 540 | for (name) |expected_c| { |
| 538 | const target_c = try in.readByte(); | 541 | const target_c = try elf.in_stream.readByte(); |
| 539 | if (target_c == 0 or expected_c != target_c) continue :section_loop; | 542 | if (target_c == 0 or expected_c != target_c) continue :section_loop; |
| 540 | } | 543 | } |
| 541 | 544 | ||
| 542 | { | 545 | { |
| 543 | const null_byte = try in.readByte(); | 546 | const null_byte = try elf.in_stream.readByte(); |
| 544 | if (null_byte == 0) return elf_section; | 547 | if (null_byte == 0) return elf_section; |
| 545 | } | 548 | } |
| 546 | } | 549 | } |
| ... | @@ -549,7 +552,7 @@ pub const Elf = struct { | ... | @@ -549,7 +552,7 @@ pub const Elf = struct { |
| 549 | } | 552 | } |
| 550 | 553 | ||
| 551 | pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void { | 554 | pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void { |
| 552 | try elf.in_file.seekTo(elf_section.offset); | 555 | try elf.seekable_stream.seekTo(elf_section.offset); |
| 553 | } | 556 | } |
| 554 | }; | 557 | }; |
| 555 | 558 |
std/fmt/index.zig+31-2| ... | @@ -2,6 +2,7 @@ const std = @import("../index.zig"); | ... | @@ -2,6 +2,7 @@ const std = @import("../index.zig"); |
| 2 | const math = std.math; | 2 | const math = std.math; |
| 3 | const debug = std.debug; | 3 | const debug = std.debug; |
| 4 | const assert = debug.assert; | 4 | const assert = debug.assert; |
| 5 | const assertError = debug.assertError; | ||
| 5 | const mem = std.mem; | 6 | const mem = std.mem; |
| 6 | const builtin = @import("builtin"); | 7 | const builtin = @import("builtin"); |
| 7 | const errol = @import("errol/index.zig"); | 8 | const errol = @import("errol/index.zig"); |
| ... | @@ -811,13 +812,41 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned | ... | @@ -811,13 +812,41 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned |
| 811 | 812 | ||
| 812 | for (buf) |c| { | 813 | for (buf) |c| { |
| 813 | const digit = try charToDigit(c, radix); | 814 | const digit = try charToDigit(c, radix); |
| 814 | x = try math.mul(T, x, radix); | 815 | |
| 815 | x = try math.add(T, x, digit); | 816 | if (x != 0) x = try math.mul(T, x, try math.cast(T, radix)); |
| 817 | x = try math.add(T, x, try math.cast(T, digit)); | ||
| 816 | } | 818 | } |
| 817 | 819 | ||
| 818 | return x; | 820 | return x; |
| 819 | } | 821 | } |
| 820 | 822 | ||
| 823 | test "parseUnsigned" { | ||
| 824 | assert((try parseUnsigned(u16, "050124", 10)) == 50124); | ||
| 825 | assert((try parseUnsigned(u16, "65535", 10)) == 65535); | ||
| 826 | assertError(parseUnsigned(u16, "65536", 10), error.Overflow); | ||
| 827 | |||
| 828 | assert((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff); | ||
| 829 | assertError(parseUnsigned(u64, "10000000000000000", 16), error.Overflow); | ||
| 830 | |||
| 831 | assert((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF); | ||
| 832 | |||
| 833 | assert((try parseUnsigned(u7, "1", 10)) == 1); | ||
| 834 | assert((try parseUnsigned(u7, "1000", 2)) == 8); | ||
| 835 | |||
| 836 | assertError(parseUnsigned(u32, "f", 10), error.InvalidCharacter); | ||
| 837 | assertError(parseUnsigned(u8, "109", 8), error.InvalidCharacter); | ||
| 838 | |||
| 839 | assert((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747); | ||
| 840 | |||
| 841 | // these numbers should fit even though the radix itself doesn't fit in the destination type | ||
| 842 | assert((try parseUnsigned(u1, "0", 10)) == 0); | ||
| 843 | assert((try parseUnsigned(u1, "1", 10)) == 1); | ||
| 844 | assertError(parseUnsigned(u1, "2", 10), error.Overflow); | ||
| 845 | assert((try parseUnsigned(u1, "001", 16)) == 1); | ||
| 846 | assert((try parseUnsigned(u2, "3", 16)) == 3); | ||
| 847 | assertError(parseUnsigned(u2, "4", 16), error.Overflow); | ||
| 848 | } | ||
| 849 | |||
| 821 | pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { | 850 | pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { |
| 822 | const value = switch (c) { | 851 | const value = switch (c) { |
| 823 | '0'...'9' => c - '0', | 852 | '0'...'9' => c - '0', |
std/hash_map.zig+14| ... | @@ -126,6 +126,14 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 | ... | @@ -126,6 +126,14 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3 |
| 126 | }; | 126 | }; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | pub fn getOrPutValue(self: *Self, key: K, value: V) !*KV { | ||
| 130 | const res = try self.getOrPut(key); | ||
| 131 | if (!res.found_existing) | ||
| 132 | res.kv.value = value; | ||
| 133 | |||
| 134 | return res.kv; | ||
| 135 | } | ||
| 136 | |||
| 129 | fn ensureCapacity(self: *Self) !void { | 137 | fn ensureCapacity(self: *Self) !void { |
| 130 | if (self.entries.len == 0) { | 138 | if (self.entries.len == 0) { |
| 131 | return self.initCapacity(16); | 139 | return self.initCapacity(16); |
| ... | @@ -354,6 +362,12 @@ test "basic hash map usage" { | ... | @@ -354,6 +362,12 @@ test "basic hash map usage" { |
| 354 | gop2.kv.value = 42; | 362 | gop2.kv.value = 42; |
| 355 | assert(map.get(99).?.value == 42); | 363 | assert(map.get(99).?.value == 42); |
| 356 | 364 | ||
| 365 | const gop3 = try map.getOrPutValue(5, 5); | ||
| 366 | assert(gop3.value == 77); | ||
| 367 | |||
| 368 | const gop4 = try map.getOrPutValue(100, 41); | ||
| 369 | assert(gop4.value == 41); | ||
| 370 | |||
| 357 | assert(map.contains(2)); | 371 | assert(map.contains(2)); |
| 358 | assert(map.get(2).?.value == 22); | 372 | assert(map.get(2).?.value == 22); |
| 359 | _ = map.remove(2); | 373 | _ = map.remove(2); |
std/io.zig+64-14| ... | @@ -32,6 +32,8 @@ pub fn getStdIn() GetStdIoErrs!File { | ... | @@ -32,6 +32,8 @@ pub fn getStdIn() GetStdIoErrs!File { |
| 32 | return File.openHandle(handle); | 32 | return File.openHandle(handle); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream; | ||
| 36 | |||
| 35 | pub fn InStream(comptime ReadError: type) type { | 37 | pub fn InStream(comptime ReadError: type) type { |
| 36 | return struct { | 38 | return struct { |
| 37 | const Self = @This(); | 39 | const Self = @This(); |
| ... | @@ -683,25 +685,73 @@ test "import io tests" { | ... | @@ -683,25 +685,73 @@ test "import io tests" { |
| 683 | } | 685 | } |
| 684 | } | 686 | } |
| 685 | 687 | ||
| 686 | pub fn readLine(buf: []u8) !usize { | 688 | pub fn readLine(buf: *std.Buffer) ![]u8 { |
| 687 | var stdin = getStdIn() catch return error.StdInUnavailable; | 689 | var stdin = try getStdIn(); |
| 688 | var adapter = stdin.inStream(); | 690 | var stdin_stream = stdin.inStream(); |
| 689 | var stream = &adapter.stream; | 691 | return readLineFrom(&stdin_stream.stream, buf); |
| 690 | var index: usize = 0; | 692 | } |
| 693 | |||
| 694 | /// Reads all characters until the next newline into buf, and returns | ||
| 695 | /// a slice of the characters read (excluding the newline character(s)). | ||
| 696 | pub fn readLineFrom(stream: var, buf: *std.Buffer) ![]u8 { | ||
| 697 | const start = buf.len(); | ||
| 691 | while (true) { | 698 | while (true) { |
| 692 | const byte = stream.readByte() catch return error.EndOfFile; | 699 | const byte = try stream.readByte(); |
| 693 | switch (byte) { | 700 | switch (byte) { |
| 694 | '\r' => { | 701 | '\r' => { |
| 695 | // trash the following \n | 702 | // trash the following \n |
| 696 | _ = stream.readByte() catch return error.EndOfFile; | 703 | _ = try stream.readByte(); |
| 697 | return index; | 704 | return buf.toSlice()[start..]; |
| 698 | }, | ||
| 699 | '\n' => return index, | ||
| 700 | else => { | ||
| 701 | if (index == buf.len) return error.InputTooLong; | ||
| 702 | buf[index] = byte; | ||
| 703 | index += 1; | ||
| 704 | }, | 705 | }, |
| 706 | '\n' => return buf.toSlice()[start..], | ||
| 707 | else => try buf.appendByte(byte), | ||
| 705 | } | 708 | } |
| 706 | } | 709 | } |
| 707 | } | 710 | } |
| 711 | |||
| 712 | test "io.readLineFrom" { | ||
| 713 | var bytes: [128]u8 = undefined; | ||
| 714 | const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator; | ||
| 715 | |||
| 716 | var buf = try std.Buffer.initSize(allocator, 0); | ||
| 717 | var mem_stream = SliceInStream.init( | ||
| 718 | \\Line 1 | ||
| 719 | \\Line 22 | ||
| 720 | \\Line 333 | ||
| 721 | ); | ||
| 722 | const stream = &mem_stream.stream; | ||
| 723 | |||
| 724 | debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf))); | ||
| 725 | debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf))); | ||
| 726 | debug.assertError(readLineFrom(stream, &buf), error.EndOfStream); | ||
| 727 | debug.assert(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333")); | ||
| 728 | } | ||
| 729 | |||
| 730 | pub fn readLineSlice(slice: []u8) ![]u8 { | ||
| 731 | var stdin = try getStdIn(); | ||
| 732 | var stdin_stream = stdin.inStream(); | ||
| 733 | return readLineSliceFrom(&stdin_stream.stream, slice); | ||
| 734 | } | ||
| 735 | |||
| 736 | /// Reads all characters until the next newline into slice, and returns | ||
| 737 | /// a slice of the characters read (excluding the newline character(s)). | ||
| 738 | pub fn readLineSliceFrom(stream: var, slice: []u8) ![]u8 { | ||
| 739 | // We cannot use Buffer.fromOwnedSlice, as it wants to append a null byte | ||
| 740 | // after taking ownership, which would always require an allocation. | ||
| 741 | var buf = std.Buffer{ .list = std.ArrayList(u8).fromOwnedSlice(debug.failing_allocator, slice) }; | ||
| 742 | try buf.resize(0); | ||
| 743 | return try readLineFrom(stream, &buf); | ||
| 744 | } | ||
| 745 | |||
| 746 | test "io.readLineSliceFrom" { | ||
| 747 | var buf: [7]u8 = undefined; | ||
| 748 | var mem_stream = SliceInStream.init( | ||
| 749 | \\Line 1 | ||
| 750 | \\Line 22 | ||
| 751 | \\Line 333 | ||
| 752 | ); | ||
| 753 | const stream = &mem_stream.stream; | ||
| 754 | |||
| 755 | debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..]))); | ||
| 756 | debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory); | ||
| 757 | } |
std/io/seekable_stream.zig created+32| ... | @@ -0,0 +1,32 @@ | ||
| 1 | const std = @import("../index.zig"); | ||
| 2 | const InStream = std.io.InStream; | ||
| 3 | |||
| 4 | pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type { | ||
| 5 | return struct { | ||
| 6 | const Self = @This(); | ||
| 7 | pub const SeekError = SeekErrorType; | ||
| 8 | pub const GetSeekPosError = GetSeekPosErrorType; | ||
| 9 | |||
| 10 | seekToFn: fn (self: *Self, pos: usize) SeekError!void, | ||
| 11 | seekForwardFn: fn (self: *Self, pos: isize) SeekError!void, | ||
| 12 | |||
| 13 | getPosFn: fn (self: *Self) GetSeekPosError!usize, | ||
| 14 | getEndPosFn: fn (self: *Self) GetSeekPosError!usize, | ||
| 15 | |||
| 16 | pub fn seekTo(self: *Self, pos: usize) SeekError!void { | ||
| 17 | return self.seekToFn(self, pos); | ||
| 18 | } | ||
| 19 | |||
| 20 | pub fn seekForward(self: *Self, amt: isize) SeekError!void { | ||
| 21 | return self.seekForwardFn(self, amt); | ||
| 22 | } | ||
| 23 | |||
| 24 | pub fn getEndPos(self: *Self) GetSeekPosError!usize { | ||
| 25 | return self.getEndPosFn(self); | ||
| 26 | } | ||
| 27 | |||
| 28 | pub fn getPos(self: *Self) GetSeekPosError!usize { | ||
| 29 | return self.getPosFn(self); | ||
| 30 | } | ||
| 31 | }; | ||
| 32 | } | ||
std/linked_list.zig+96| ... | @@ -82,6 +82,28 @@ pub fn LinkedList(comptime T: type) type { | ... | @@ -82,6 +82,28 @@ pub fn LinkedList(comptime T: type) type { |
| 82 | list.len += 1; | 82 | list.len += 1; |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | /// Concatenate list2 onto the end of list1, removing all entries from the former. | ||
| 86 | /// | ||
| 87 | /// Arguments: | ||
| 88 | /// list1: the list to concatenate onto | ||
| 89 | /// list2: the list to be concatenated | ||
| 90 | pub fn concatByMoving(list1: *Self, list2: *Self) void { | ||
| 91 | const l2_first = list2.first orelse return; | ||
| 92 | if (list1.last) |l1_last| { | ||
| 93 | l1_last.next = list2.first; | ||
| 94 | l2_first.prev = list1.last; | ||
| 95 | list1.len += list2.len; | ||
| 96 | } else { | ||
| 97 | // list1 was empty | ||
| 98 | list1.first = list2.first; | ||
| 99 | list1.len = list2.len; | ||
| 100 | } | ||
| 101 | list1.last = list2.last; | ||
| 102 | list2.first = null; | ||
| 103 | list2.last = null; | ||
| 104 | list2.len = 0; | ||
| 105 | } | ||
| 106 | |||
| 85 | /// Insert a new node at the end of the list. | 107 | /// Insert a new node at the end of the list. |
| 86 | /// | 108 | /// |
| 87 | /// Arguments: | 109 | /// Arguments: |
| ... | @@ -247,3 +269,77 @@ test "basic linked list test" { | ... | @@ -247,3 +269,77 @@ test "basic linked list test" { |
| 247 | assert(list.last.?.data == 4); | 269 | assert(list.last.?.data == 4); |
| 248 | assert(list.len == 2); | 270 | assert(list.len == 2); |
| 249 | } | 271 | } |
| 272 | |||
| 273 | test "linked list concatenation" { | ||
| 274 | const allocator = debug.global_allocator; | ||
| 275 | var list1 = LinkedList(u32).init(); | ||
| 276 | var list2 = LinkedList(u32).init(); | ||
| 277 | |||
| 278 | var one = try list1.createNode(1, allocator); | ||
| 279 | defer list1.destroyNode(one, allocator); | ||
| 280 | var two = try list1.createNode(2, allocator); | ||
| 281 | defer list1.destroyNode(two, allocator); | ||
| 282 | var three = try list1.createNode(3, allocator); | ||
| 283 | defer list1.destroyNode(three, allocator); | ||
| 284 | var four = try list1.createNode(4, allocator); | ||
| 285 | defer list1.destroyNode(four, allocator); | ||
| 286 | var five = try list1.createNode(5, allocator); | ||
| 287 | defer list1.destroyNode(five, allocator); | ||
| 288 | |||
| 289 | list1.append(one); | ||
| 290 | list1.append(two); | ||
| 291 | list2.append(three); | ||
| 292 | list2.append(four); | ||
| 293 | list2.append(five); | ||
| 294 | |||
| 295 | list1.concatByMoving(&list2); | ||
| 296 | |||
| 297 | assert(list1.last == five); | ||
| 298 | assert(list1.len == 5); | ||
| 299 | assert(list2.first == null); | ||
| 300 | assert(list2.last == null); | ||
| 301 | assert(list2.len == 0); | ||
| 302 | |||
| 303 | // Traverse forwards. | ||
| 304 | { | ||
| 305 | var it = list1.first; | ||
| 306 | var index: u32 = 1; | ||
| 307 | while (it) |node| : (it = node.next) { | ||
| 308 | assert(node.data == index); | ||
| 309 | index += 1; | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | // Traverse backwards. | ||
| 314 | { | ||
| 315 | var it = list1.last; | ||
| 316 | var index: u32 = 1; | ||
| 317 | while (it) |node| : (it = node.prev) { | ||
| 318 | assert(node.data == (6 - index)); | ||
| 319 | index += 1; | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | // Swap them back, this verifies that concating to an empty list works. | ||
| 324 | list2.concatByMoving(&list1); | ||
| 325 | |||
| 326 | // Traverse forwards. | ||
| 327 | { | ||
| 328 | var it = list2.first; | ||
| 329 | var index: u32 = 1; | ||
| 330 | while (it) |node| : (it = node.next) { | ||
| 331 | assert(node.data == index); | ||
| 332 | index += 1; | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | // Traverse backwards. | ||
| 337 | { | ||
| 338 | var it = list2.last; | ||
| 339 | var index: u32 = 1; | ||
| 340 | while (it) |node| : (it = node.prev) { | ||
| 341 | assert(node.data == (6 - index)); | ||
| 342 | index += 1; | ||
| 343 | } | ||
| 344 | } | ||
| 345 | } |
std/os/file.zig+59-5| ... | @@ -228,7 +228,14 @@ pub const File = struct { | ... | @@ -228,7 +228,14 @@ pub const File = struct { |
| 228 | return os.isTty(self.handle); | 228 | return os.isTty(self.handle); |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | pub fn seekForward(self: File, amount: isize) !void { | 231 | pub const SeekError = error{ |
| 232 | /// TODO make this error impossible to get | ||
| 233 | Overflow, | ||
| 234 | Unseekable, | ||
| 235 | Unexpected, | ||
| 236 | }; | ||
| 237 | |||
| 238 | pub fn seekForward(self: File, amount: isize) SeekError!void { | ||
| 232 | switch (builtin.os) { | 239 | switch (builtin.os) { |
| 233 | Os.linux, Os.macosx, Os.ios, Os.freebsd => { | 240 | Os.linux, Os.macosx, Os.ios, Os.freebsd => { |
| 234 | const result = posix.lseek(self.handle, amount, posix.SEEK_CUR); | 241 | const result = posix.lseek(self.handle, amount, posix.SEEK_CUR); |
| ... | @@ -259,7 +266,7 @@ pub const File = struct { | ... | @@ -259,7 +266,7 @@ pub const File = struct { |
| 259 | } | 266 | } |
| 260 | } | 267 | } |
| 261 | 268 | ||
| 262 | pub fn seekTo(self: File, pos: usize) !void { | 269 | pub fn seekTo(self: File, pos: usize) SeekError!void { |
| 263 | switch (builtin.os) { | 270 | switch (builtin.os) { |
| 264 | Os.linux, Os.macosx, Os.ios, Os.freebsd => { | 271 | Os.linux, Os.macosx, Os.ios, Os.freebsd => { |
| 265 | const ipos = try math.cast(isize, pos); | 272 | const ipos = try math.cast(isize, pos); |
| ... | @@ -293,7 +300,14 @@ pub const File = struct { | ... | @@ -293,7 +300,14 @@ pub const File = struct { |
| 293 | } | 300 | } |
| 294 | } | 301 | } |
| 295 | 302 | ||
| 296 | pub fn getPos(self: File) !usize { | 303 | pub const GetSeekPosError = error{ |
| 304 | Overflow, | ||
| 305 | SystemResources, | ||
| 306 | Unseekable, | ||
| 307 | Unexpected, | ||
| 308 | }; | ||
| 309 | |||
| 310 | pub fn getPos(self: File) GetSeekPosError!usize { | ||
| 297 | switch (builtin.os) { | 311 | switch (builtin.os) { |
| 298 | Os.linux, Os.macosx, Os.ios, Os.freebsd => { | 312 | Os.linux, Os.macosx, Os.ios, Os.freebsd => { |
| 299 | const result = posix.lseek(self.handle, 0, posix.SEEK_CUR); | 313 | const result = posix.lseek(self.handle, 0, posix.SEEK_CUR); |
| ... | @@ -323,13 +337,13 @@ pub const File = struct { | ... | @@ -323,13 +337,13 @@ pub const File = struct { |
| 323 | } | 337 | } |
| 324 | 338 | ||
| 325 | assert(pos >= 0); | 339 | assert(pos >= 0); |
| 326 | return math.cast(usize, pos) catch error.FilePosLargerThanPointerRange; | 340 | return math.cast(usize, pos); |
| 327 | }, | 341 | }, |
| 328 | else => @compileError("unsupported OS"), | 342 | else => @compileError("unsupported OS"), |
| 329 | } | 343 | } |
| 330 | } | 344 | } |
| 331 | 345 | ||
| 332 | pub fn getEndPos(self: File) !usize { | 346 | pub fn getEndPos(self: File) GetSeekPosError!usize { |
| 333 | if (is_posix) { | 347 | if (is_posix) { |
| 334 | const stat = try os.posixFStat(self.handle); | 348 | const stat = try os.posixFStat(self.handle); |
| 335 | return @intCast(usize, stat.size); | 349 | return @intCast(usize, stat.size); |
| ... | @@ -431,6 +445,18 @@ pub const File = struct { | ... | @@ -431,6 +445,18 @@ pub const File = struct { |
| 431 | }; | 445 | }; |
| 432 | } | 446 | } |
| 433 | 447 | ||
| 448 | pub fn seekableStream(file: File) SeekableStream { | ||
| 449 | return SeekableStream{ | ||
| 450 | .file = file, | ||
| 451 | .stream = SeekableStream.Stream{ | ||
| 452 | .seekToFn = SeekableStream.seekToFn, | ||
| 453 | .seekForwardFn = SeekableStream.seekForwardFn, | ||
| 454 | .getPosFn = SeekableStream.getPosFn, | ||
| 455 | .getEndPosFn = SeekableStream.getEndPosFn, | ||
| 456 | }, | ||
| 457 | }; | ||
| 458 | } | ||
| 459 | |||
| 434 | /// Implementation of io.InStream trait for File | 460 | /// Implementation of io.InStream trait for File |
| 435 | pub const InStream = struct { | 461 | pub const InStream = struct { |
| 436 | file: File, | 462 | file: File, |
| ... | @@ -458,4 +484,32 @@ pub const File = struct { | ... | @@ -458,4 +484,32 @@ pub const File = struct { |
| 458 | return self.file.write(bytes); | 484 | return self.file.write(bytes); |
| 459 | } | 485 | } |
| 460 | }; | 486 | }; |
| 487 | |||
| 488 | /// Implementation of io.SeekableStream trait for File | ||
| 489 | pub const SeekableStream = struct { | ||
| 490 | file: File, | ||
| 491 | stream: Stream, | ||
| 492 | |||
| 493 | pub const Stream = io.SeekableStream(SeekError, GetSeekPosError); | ||
| 494 | |||
| 495 | pub fn seekToFn(seekable_stream: *Stream, pos: usize) SeekError!void { | ||
| 496 | const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); | ||
| 497 | return self.file.seekTo(pos); | ||
| 498 | } | ||
| 499 | |||
| 500 | pub fn seekForwardFn(seekable_stream: *Stream, amt: isize) SeekError!void { | ||
| 501 | const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); | ||
| 502 | return self.file.seekForward(amt); | ||
| 503 | } | ||
| 504 | |||
| 505 | pub fn getEndPosFn(seekable_stream: *Stream) GetSeekPosError!usize { | ||
| 506 | const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); | ||
| 507 | return self.file.getEndPos(); | ||
| 508 | } | ||
| 509 | |||
| 510 | pub fn getPosFn(seekable_stream: *Stream) GetSeekPosError!usize { | ||
| 511 | const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream); | ||
| 512 | return self.file.getPos(); | ||
| 513 | } | ||
| 514 | }; | ||
| 461 | }; | 515 | }; |
std/unicode.zig+1-1| ... | @@ -208,7 +208,7 @@ pub const Utf8View = struct { | ... | @@ -208,7 +208,7 @@ pub const Utf8View = struct { |
| 208 | } | 208 | } |
| 209 | }; | 209 | }; |
| 210 | 210 | ||
| 211 | const Utf8Iterator = struct { | 211 | pub const Utf8Iterator = struct { |
| 212 | bytes: []const u8, | 212 | bytes: []const u8, |
| 213 | i: usize, | 213 | i: usize, |
| 214 | 214 |
test/compile_errors.zig+16-4| ... | @@ -1,6 +1,18 @@ | ... | @@ -1,6 +1,18 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | ||
| 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4 | cases.add( | ||
| 5 | "error note for function parameter incompatibility", | ||
| 6 | \\fn do_the_thing(func: fn (arg: i32) void) void {} | ||
| 7 | \\fn bar(arg: bool) void {} | ||
| 8 | \\export fn entry() void { | ||
| 9 | \\ do_the_thing(bar); | ||
| 10 | \\} | ||
| 11 | , | ||
| 12 | ".tmp_source.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void", | ||
| 13 | ".tmp_source.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'", | ||
| 14 | ); | ||
| 15 | |||
| 4 | cases.add( | 16 | cases.add( |
| 5 | "cast negative value to unsigned integer", | 17 | "cast negative value to unsigned integer", |
| 6 | \\comptime { | 18 | \\comptime { |
| ... | @@ -5248,8 +5260,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -5248,8 +5260,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5248 | \\export fn foo() void { | 5260 | \\export fn foo() void { |
| 5249 | \\ asm volatile ("" : : [bar]"r"(3) : ""); | 5261 | \\ asm volatile ("" : : [bar]"r"(3) : ""); |
| 5250 | \\} | 5262 | \\} |
| 5251 | , | 5263 | , |
| 5252 | ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_int", | 5264 | ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_int", |
| 5253 | ); | 5265 | ); |
| 5254 | 5266 | ||
| 5255 | cases.add( | 5267 | cases.add( |
| ... | @@ -5257,7 +5269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -5257,7 +5269,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5257 | \\export fn foo() void { | 5269 | \\export fn foo() void { |
| 5258 | \\ asm volatile ("" : : [bar]"r"(3.17) : ""); | 5270 | \\ asm volatile ("" : : [bar]"r"(3.17) : ""); |
| 5259 | \\} | 5271 | \\} |
| 5260 | , | 5272 | , |
| 5261 | ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float", | 5273 | ".tmp_source.zig:2:35: error: expected sized integer or sized float, found comptime_float", |
| 5262 | ); | 5274 | ); |
| 5263 | } | 5275 | } |