authorgravatar for BenoitJGirard@users.noreply.github.comBenoitJGirard <BenoitJGirard@users.noreply.github.com> 2018-12-11 20:06:13-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2018-12-11 20:06:13-05:00
logf0ec308e26ff957c7fbb50ccc69d3d549c42c4da
tree5fbb35b30640f8c4fd616c3132d556af9a3bc11c
parent11e8afb37cea3d4b951165f382eeee36a653978f
parent5f5364ad73dc6c31e1e189596f407970f852701a
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #1 from ziglang/master

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
3434
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
9898
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
2525
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#}
4269test "ignoring expression value" {4275test "void is ignored" {
4270 foo();4276 returnsVoid();
4277}
4278
4279test "explicitly ignoring expression value" {
4280 _ = foo();
4271}4281}
42724282
4273fn foo() void {}4283fn returnsVoid() void {}
4284
4285fn foo() i32 {
4286 return 1234;
4287}
4274 {#code_end#}4288 {#code_end#}
4275 {#header_close#}4289 {#header_close#}
42764290
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;
2626
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 };
3434
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 {
67struct ConstCastOnly;67struct ConstCastOnly;
68struct ConstCastArg {68struct 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};
7274
...@@ -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: // TODO10499 case ConstCastResultIdFnAlign: // TODO
10487 case ConstCastResultIdFnCC: // TODO10500 case ConstCastResultIdFnCC: // TODO
10488 case ConstCastResultIdFnVarArgs: // TODO10501 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: // TODO10503 case ConstCastResultIdFnReturnType: // TODO
10491 case ConstCastResultIdFnArgCount: // TODO10504 case ConstCastResultIdFnArgCount: // TODO
10492 case ConstCastResultIdFnGenericArgCount: // TODO10505 case ConstCastResultIdFnGenericArgCount: // TODO
10493 case ConstCastResultIdFnArg: // TODO
10494 case ConstCastResultIdFnArgNoAlias: // TODO10506 case ConstCastResultIdFnArgNoAlias: // TODO
10495 case ConstCastResultIdUnresolvedInferredErrSet: // TODO10507 case ConstCastResultIdUnresolvedInferredErrSet: // TODO
10496 case ConstCastResultIdAsyncAllocatorType: // TODO10508 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}
682682
683683
684static_assert((Triple::ArchType)ZigLLVM_LastArchType == Triple::LastArchType, "");
685static_assert((Triple::VendorType)ZigLLVM_LastVendorType == Triple::LastVendorType, "");
686static_assert((Triple::OSType)ZigLLVM_LastOSType == Triple::LastOSType, "");
687static_assert((Triple::EnvironmentType)ZigLLVM_LastEnvironmentType == Triple::LastEnvironmentType, "");
688static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v5 == Triple::KalimbaSubArch_v5, "");
689
690static_assert((Triple::ObjectFormatType)ZigLLVM_UnknownObjectFormat == Triple::UnknownObjectFormat, "");
691static_assert((Triple::ObjectFormatType)ZigLLVM_COFF == Triple::COFF, "");
692static_assert((Triple::ObjectFormatType)ZigLLVM_ELF == Triple::ELF, "");
693static_assert((Triple::ObjectFormatType)ZigLLVM_MachO == Triple::MachO, "");
694static_assert((Triple::ObjectFormatType)ZigLLVM_Wasm == Triple::Wasm, "");
695
696const char *ZigLLVMGetArchTypeName(ZigLLVM_ArchType arch) {684const 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); // unreachable907 assert(false); // unreachable
920 abort();908 abort();
921}909}
910
911static_assert((Triple::ArchType)ZigLLVM_UnknownArch == Triple::UnknownArch, "");
912static_assert((Triple::ArchType)ZigLLVM_arm == Triple::arm, "");
913static_assert((Triple::ArchType)ZigLLVM_armeb == Triple::armeb, "");
914static_assert((Triple::ArchType)ZigLLVM_aarch64 == Triple::aarch64, "");
915static_assert((Triple::ArchType)ZigLLVM_aarch64_be == Triple::aarch64_be, "");
916static_assert((Triple::ArchType)ZigLLVM_arc == Triple::arc, "");
917static_assert((Triple::ArchType)ZigLLVM_avr == Triple::avr, "");
918static_assert((Triple::ArchType)ZigLLVM_bpfel == Triple::bpfel, "");
919static_assert((Triple::ArchType)ZigLLVM_bpfeb == Triple::bpfeb, "");
920static_assert((Triple::ArchType)ZigLLVM_hexagon == Triple::hexagon, "");
921static_assert((Triple::ArchType)ZigLLVM_mips == Triple::mips, "");
922static_assert((Triple::ArchType)ZigLLVM_mipsel == Triple::mipsel, "");
923static_assert((Triple::ArchType)ZigLLVM_mips64 == Triple::mips64, "");
924static_assert((Triple::ArchType)ZigLLVM_mips64el == Triple::mips64el, "");
925static_assert((Triple::ArchType)ZigLLVM_msp430 == Triple::msp430, "");
926static_assert((Triple::ArchType)ZigLLVM_nios2 == Triple::nios2, "");
927static_assert((Triple::ArchType)ZigLLVM_ppc == Triple::ppc, "");
928static_assert((Triple::ArchType)ZigLLVM_ppc64 == Triple::ppc64, "");
929static_assert((Triple::ArchType)ZigLLVM_ppc64le == Triple::ppc64le, "");
930static_assert((Triple::ArchType)ZigLLVM_r600 == Triple::r600, "");
931static_assert((Triple::ArchType)ZigLLVM_amdgcn == Triple::amdgcn, "");
932static_assert((Triple::ArchType)ZigLLVM_riscv32 == Triple::riscv32, "");
933static_assert((Triple::ArchType)ZigLLVM_riscv64 == Triple::riscv64, "");
934static_assert((Triple::ArchType)ZigLLVM_sparc == Triple::sparc, "");
935static_assert((Triple::ArchType)ZigLLVM_sparcv9 == Triple::sparcv9, "");
936static_assert((Triple::ArchType)ZigLLVM_sparcel == Triple::sparcel, "");
937static_assert((Triple::ArchType)ZigLLVM_systemz == Triple::systemz, "");
938static_assert((Triple::ArchType)ZigLLVM_tce == Triple::tce, "");
939static_assert((Triple::ArchType)ZigLLVM_tcele == Triple::tcele, "");
940static_assert((Triple::ArchType)ZigLLVM_thumb == Triple::thumb, "");
941static_assert((Triple::ArchType)ZigLLVM_thumbeb == Triple::thumbeb, "");
942static_assert((Triple::ArchType)ZigLLVM_x86 == Triple::x86, "");
943static_assert((Triple::ArchType)ZigLLVM_x86_64 == Triple::x86_64, "");
944static_assert((Triple::ArchType)ZigLLVM_xcore == Triple::xcore, "");
945static_assert((Triple::ArchType)ZigLLVM_nvptx == Triple::nvptx, "");
946static_assert((Triple::ArchType)ZigLLVM_nvptx64 == Triple::nvptx64, "");
947static_assert((Triple::ArchType)ZigLLVM_le32 == Triple::le32, "");
948static_assert((Triple::ArchType)ZigLLVM_le64 == Triple::le64, "");
949static_assert((Triple::ArchType)ZigLLVM_amdil == Triple::amdil, "");
950static_assert((Triple::ArchType)ZigLLVM_amdil64 == Triple::amdil64, "");
951static_assert((Triple::ArchType)ZigLLVM_hsail == Triple::hsail, "");
952static_assert((Triple::ArchType)ZigLLVM_hsail64 == Triple::hsail64, "");
953static_assert((Triple::ArchType)ZigLLVM_spir == Triple::spir, "");
954static_assert((Triple::ArchType)ZigLLVM_spir64 == Triple::spir64, "");
955static_assert((Triple::ArchType)ZigLLVM_kalimba == Triple::kalimba, "");
956static_assert((Triple::ArchType)ZigLLVM_shave == Triple::shave, "");
957static_assert((Triple::ArchType)ZigLLVM_lanai == Triple::lanai, "");
958static_assert((Triple::ArchType)ZigLLVM_wasm32 == Triple::wasm32, "");
959static_assert((Triple::ArchType)ZigLLVM_wasm64 == Triple::wasm64, "");
960static_assert((Triple::ArchType)ZigLLVM_renderscript32 == Triple::renderscript32, "");
961static_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
965static_assert((Triple::SubArchType)ZigLLVM_NoSubArch == Triple::NoSubArch, "");
966static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_4a == Triple::ARMSubArch_v8_4a, "");
967static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_3a == Triple::ARMSubArch_v8_3a, "");
968static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_2a == Triple::ARMSubArch_v8_2a, "");
969static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_1a == Triple::ARMSubArch_v8_1a, "");
970static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8 == Triple::ARMSubArch_v8, "");
971static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8r == Triple::ARMSubArch_v8r, "");
972static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8m_baseline == Triple::ARMSubArch_v8m_baseline, "");
973static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8m_mainline == Triple::ARMSubArch_v8m_mainline, "");
974static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7 == Triple::ARMSubArch_v7, "");
975static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7em == Triple::ARMSubArch_v7em, "");
976static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7m == Triple::ARMSubArch_v7m, "");
977static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7s == Triple::ARMSubArch_v7s, "");
978static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7k == Triple::ARMSubArch_v7k, "");
979static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7ve == Triple::ARMSubArch_v7ve, "");
980static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6 == Triple::ARMSubArch_v6, "");
981static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6m == Triple::ARMSubArch_v6m, "");
982static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6k == Triple::ARMSubArch_v6k, "");
983static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6t2 == Triple::ARMSubArch_v6t2, "");
984static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v5 == Triple::ARMSubArch_v5, "");
985static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v5te == Triple::ARMSubArch_v5te, "");
986static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v4t == Triple::ARMSubArch_v4t, "");
987static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v3 == Triple::KalimbaSubArch_v3, "");
988static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v4 == Triple::KalimbaSubArch_v4, "");
989static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v5 == Triple::KalimbaSubArch_v5, "");
990
991static_assert((Triple::VendorType)ZigLLVM_UnknownVendor == Triple::UnknownVendor, "");
992static_assert((Triple::VendorType)ZigLLVM_Apple == Triple::Apple, "");
993static_assert((Triple::VendorType)ZigLLVM_PC == Triple::PC, "");
994static_assert((Triple::VendorType)ZigLLVM_SCEI == Triple::SCEI, "");
995static_assert((Triple::VendorType)ZigLLVM_BGP == Triple::BGP, "");
996static_assert((Triple::VendorType)ZigLLVM_BGQ == Triple::BGQ, "");
997static_assert((Triple::VendorType)ZigLLVM_Freescale == Triple::Freescale, "");
998static_assert((Triple::VendorType)ZigLLVM_IBM == Triple::IBM, "");
999static_assert((Triple::VendorType)ZigLLVM_ImaginationTechnologies == Triple::ImaginationTechnologies, "");
1000static_assert((Triple::VendorType)ZigLLVM_MipsTechnologies == Triple::MipsTechnologies, "");
1001static_assert((Triple::VendorType)ZigLLVM_NVIDIA == Triple::NVIDIA, "");
1002static_assert((Triple::VendorType)ZigLLVM_CSR == Triple::CSR, "");
1003static_assert((Triple::VendorType)ZigLLVM_Myriad == Triple::Myriad, "");
1004static_assert((Triple::VendorType)ZigLLVM_AMD == Triple::AMD, "");
1005static_assert((Triple::VendorType)ZigLLVM_Mesa == Triple::Mesa, "");
1006static_assert((Triple::VendorType)ZigLLVM_SUSE == Triple::SUSE, "");
1007static_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
1011static_assert((Triple::OSType)ZigLLVM_UnknownOS == Triple::UnknownOS, "");
1012static_assert((Triple::OSType)ZigLLVM_Ananas == Triple::Ananas, "");
1013static_assert((Triple::OSType)ZigLLVM_CloudABI == Triple::CloudABI, "");
1014static_assert((Triple::OSType)ZigLLVM_Darwin == Triple::Darwin, "");
1015static_assert((Triple::OSType)ZigLLVM_DragonFly == Triple::DragonFly, "");
1016static_assert((Triple::OSType)ZigLLVM_FreeBSD == Triple::FreeBSD, "");
1017static_assert((Triple::OSType)ZigLLVM_Fuchsia == Triple::Fuchsia, "");
1018static_assert((Triple::OSType)ZigLLVM_IOS == Triple::IOS, "");
1019static_assert((Triple::OSType)ZigLLVM_KFreeBSD == Triple::KFreeBSD, "");
1020static_assert((Triple::OSType)ZigLLVM_Linux == Triple::Linux, "");
1021static_assert((Triple::OSType)ZigLLVM_Lv2 == Triple::Lv2, "");
1022static_assert((Triple::OSType)ZigLLVM_MacOSX == Triple::MacOSX, "");
1023static_assert((Triple::OSType)ZigLLVM_NetBSD == Triple::NetBSD, "");
1024static_assert((Triple::OSType)ZigLLVM_OpenBSD == Triple::OpenBSD, "");
1025static_assert((Triple::OSType)ZigLLVM_Solaris == Triple::Solaris, "");
1026static_assert((Triple::OSType)ZigLLVM_Win32 == Triple::Win32, "");
1027static_assert((Triple::OSType)ZigLLVM_Haiku == Triple::Haiku, "");
1028static_assert((Triple::OSType)ZigLLVM_Minix == Triple::Minix, "");
1029static_assert((Triple::OSType)ZigLLVM_RTEMS == Triple::RTEMS, "");
1030static_assert((Triple::OSType)ZigLLVM_NaCl == Triple::NaCl, "");
1031static_assert((Triple::OSType)ZigLLVM_CNK == Triple::CNK, "");
1032static_assert((Triple::OSType)ZigLLVM_AIX == Triple::AIX, "");
1033static_assert((Triple::OSType)ZigLLVM_CUDA == Triple::CUDA, "");
1034static_assert((Triple::OSType)ZigLLVM_NVCL == Triple::NVCL, "");
1035static_assert((Triple::OSType)ZigLLVM_AMDHSA == Triple::AMDHSA, "");
1036static_assert((Triple::OSType)ZigLLVM_PS4 == Triple::PS4, "");
1037static_assert((Triple::OSType)ZigLLVM_ELFIAMCU == Triple::ELFIAMCU, "");
1038static_assert((Triple::OSType)ZigLLVM_TvOS == Triple::TvOS, "");
1039static_assert((Triple::OSType)ZigLLVM_WatchOS == Triple::WatchOS, "");
1040static_assert((Triple::OSType)ZigLLVM_Mesa3D == Triple::Mesa3D, "");
1041static_assert((Triple::OSType)ZigLLVM_Contiki == Triple::Contiki, "");
1042static_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
1046static_assert((Triple::EnvironmentType)ZigLLVM_UnknownEnvironment == Triple::UnknownEnvironment, "");
1047static_assert((Triple::EnvironmentType)ZigLLVM_GNU == Triple::GNU, "");
1048static_assert((Triple::EnvironmentType)ZigLLVM_GNUABIN32 == Triple::GNUABIN32, "");
1049static_assert((Triple::EnvironmentType)ZigLLVM_GNUABI64 == Triple::GNUABI64, "");
1050static_assert((Triple::EnvironmentType)ZigLLVM_GNUEABI == Triple::GNUEABI, "");
1051static_assert((Triple::EnvironmentType)ZigLLVM_GNUEABIHF == Triple::GNUEABIHF, "");
1052static_assert((Triple::EnvironmentType)ZigLLVM_GNUX32 == Triple::GNUX32, "");
1053static_assert((Triple::EnvironmentType)ZigLLVM_CODE16 == Triple::CODE16, "");
1054static_assert((Triple::EnvironmentType)ZigLLVM_EABI == Triple::EABI, "");
1055static_assert((Triple::EnvironmentType)ZigLLVM_EABIHF == Triple::EABIHF, "");
1056static_assert((Triple::EnvironmentType)ZigLLVM_Android == Triple::Android, "");
1057static_assert((Triple::EnvironmentType)ZigLLVM_Musl == Triple::Musl, "");
1058static_assert((Triple::EnvironmentType)ZigLLVM_MuslEABI == Triple::MuslEABI, "");
1059static_assert((Triple::EnvironmentType)ZigLLVM_MuslEABIHF == Triple::MuslEABIHF, "");
1060static_assert((Triple::EnvironmentType)ZigLLVM_MSVC == Triple::MSVC, "");
1061static_assert((Triple::EnvironmentType)ZigLLVM_Itanium == Triple::Itanium, "");
1062static_assert((Triple::EnvironmentType)ZigLLVM_Cygnus == Triple::Cygnus, "");
1063static_assert((Triple::EnvironmentType)ZigLLVM_CoreCLR == Triple::CoreCLR, "");
1064static_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
1068static_assert((Triple::ObjectFormatType)ZigLLVM_UnknownObjectFormat == Triple::UnknownObjectFormat, "");
1069static_assert((Triple::ObjectFormatType)ZigLLVM_COFF == Triple::COFF, "");
1070static_assert((Triple::ObjectFormatType)ZigLLVM_ELF == Triple::ELF, "");
1071static_assert((Triple::ObjectFormatType)ZigLLVM_MachO == Triple::MachO, "");
1072static_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 }
151151
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 }
155159
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};
809813
814const Pkg = struct {
815 name: []const u8,
816 path: []const u8,
817};
818
810pub const LibExeObjStep = struct {819pub 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,
851860
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 }
893897
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 }
898902
...@@ -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 }
12731280
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 }
16971706
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 }
18731889
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}
200200
201pub inline fn getReturnAddress(frame_count: usize) usize {201pub 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};
210231
211pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {232pub 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];
288283
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
414409
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}
613616
614pub 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
619pub 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}
639658
659pub 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
640fn printLineInfo(663fn 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}
874897
875fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {898fn 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}
901905
902pub 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
905909/// * compile_unit_list
906 section_loop: for (elf.section_headers) |*elf_section| {910pub 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);
908912 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 }
916915
917 {916pub 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}
922940
923 return null;941fn 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}
925961
926fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {962fn 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}
10021038
1003fn printLineFromFile(out_stream: var, line_info: LineInfo) !void {1039fn 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 size1042 // 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};
10551091
1092pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
1093pub const DwarfInStream = io.InStream(anyerror);
1094
1095pub 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
1056pub const DebugInfo = switch (builtin.os) {1121pub 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 }
12081248
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};
12251265
1226const LineInfo = struct {1266pub 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,
12311271
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};
12361277
...@@ -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}
13231364
1324fn getString(st: *DebugInfo, offset: u64) ![]u8 {1365fn 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}
13291370
1330fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {1371fn 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}
13731414
1374const ParseFormValueError = error{1415fn 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
1381fn 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}
14301464
1431fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {1465fn 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;
14461477
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 {
14581489
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.
1461fn getAbbrevTable(st: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable {1492fn 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}
14741505
1475fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {1506fn 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}
14811512
1482fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {1513fn 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;
14881516
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}
17011729
1702fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo {1730fn 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);
17041732
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;
17091736
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);
17151739
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));
17201744
...@@ -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 }
17251749
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 51751 // 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;
17291753
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;
17321756
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;
17351759
1736 if (version >= 4) {1760 if (version >= 4) {
1737 // maximum_operations_per_instruction1761 // maximum_operations_per_instruction
1738 _ = try in_stream.readByte();1762 _ = try di.dwarf_in_stream.readByte();
1739 }1763 }
17401764
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();
17431767
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;
17461770
1747 const opcode_base = try in_stream.readByte();1771 const opcode_base = try di.dwarf_in_stream.readByte();
17481772
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);
17501774
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 }
17571781
...@@ -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 }
17821806
1783 try in_file.seekTo(prog_start_offset);1807 try di.dwarf_seekable_stream.seekTo(prog_start_offset);
17841808
1785 while (true) {1809 while (true) {
1786 const opcode = try in_stream.readByte();1810 const opcode = try di.dwarf_in_stream.readByte();
17871811
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}
18791903
1880fn scanAllCompileUnits(st: *DebugInfo) !void {1904fn 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;
18841908
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);
18901911
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));
18951916
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;
18981919
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);
19001921
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;
19031924
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);
19061927
1907 try st.self_exe_file.seekTo(compile_unit_pos);1928 try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
19081929
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));
19101931
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;
19121933
...@@ -1934,7 +1955,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {...@@ -1934,7 +1955,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
1934 }1955 }
1935 };1956 };
19361957
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}
19491970
1950fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit {1971fn 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};
354354
355pub const Elf = struct {355pub 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 {
370371
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 }
377376
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;
383381
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;
386392
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;
405411
406 // skip over padding412 // skip over padding
407 try elf.in_file.seekForward(9);413 try seekable_stream.seekForward(9);
408414
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 }
442448
443 // skip over flags449 // skip over flags
444 try elf.in_file.seekForward(4);450 try seekable_stream.seekForward(4);
445451
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);
463469
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 }
468474
469 try elf.in_file.seekTo(elf.section_header_offset);475 try seekable_stream.seekTo(elf.section_header_offset);
470476
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);
523529
524 if (elf.auto_close_stream) elf.in_file.close();530 if (elf.auto_close_stream) elf.prealloc_file.close();
525 }531 }
526532
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;
533536
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);
536539
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 }
541544
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 }
550553
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};
555558
std/fmt/index.zig+31-2
...@@ -2,6 +2,7 @@ const std = @import("../index.zig");...@@ -2,6 +2,7 @@ const std = @import("../index.zig");
2const math = std.math;2const math = std.math;
3const debug = std.debug;3const debug = std.debug;
4const assert = debug.assert;4const assert = debug.assert;
5const assertError = debug.assertError;
5const mem = std.mem;6const mem = std.mem;
6const builtin = @import("builtin");7const builtin = @import("builtin");
7const errol = @import("errol/index.zig");8const 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
811812
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 }
817819
818 return x;820 return x;
819}821}
820822
823test "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
821pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {850pub 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 }
128128
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);
356364
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}
3434
35pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
36
35pub fn InStream(comptime ReadError: type) type {37pub 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}
685687
686pub fn readLine(buf: []u8) !usize {688pub 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)).
696pub 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 \n702 // 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
712test "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
730pub 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)).
738pub 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
746test "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 @@
1const std = @import("../index.zig");
2const InStream = std.io.InStream;
3
4pub 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 }
8484
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
273test "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 }
230230
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 }
261268
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 }
295302
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 }
324338
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 }
331345
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 }
433447
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 File460 /// 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};
210210
211const Utf8Iterator = struct {211pub const Utf8Iterator = struct {
212 bytes: []const u8,212 bytes: []const u8,
213 i: usize,213 i: usize,
214214
test/compile_errors.zig+16-4
...@@ -1,6 +1,18 @@...@@ -1,6 +1,18 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompileErrorContext) void {3pub 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 );
52545266
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}