commit
f0ec308e26
|
@ -491,6 +491,7 @@ set(ZIG_STD_FILES
|
|||
"heap.zig"
|
||||
"index.zig"
|
||||
"io.zig"
|
||||
"io/seekable_stream.zig"
|
||||
"json.zig"
|
||||
"lazy_init.zig"
|
||||
"linked_list.zig"
|
||||
|
|
|
@ -34,6 +34,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then
|
|||
|
||||
SHASUM=$(sha256sum $ARTIFACTSDIR/$TARBALL | cut '-d ' -f1)
|
||||
BYTESIZE=$(wc -c < $ARTIFACTSDIR/$TARBALL)
|
||||
# `set -x` causes these variables to be mangled.
|
||||
# See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html
|
||||
set +x
|
||||
echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL"
|
||||
echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM"
|
||||
echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE"
|
||||
|
|
|
@ -98,6 +98,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then
|
|||
|
||||
SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1)
|
||||
BYTESIZE=$(wc -c < $TARBALL)
|
||||
# `set -x` causes these variables to be mangled.
|
||||
# See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html
|
||||
set +x
|
||||
echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL"
|
||||
echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM"
|
||||
echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE"
|
||||
|
|
|
@ -25,6 +25,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then
|
|||
|
||||
SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1)
|
||||
BYTESIZE=$(wc -c < $TARBALL)
|
||||
# `set -x` causes these variables to be mangled.
|
||||
# See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html
|
||||
set +x
|
||||
echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL"
|
||||
echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM"
|
||||
echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE"
|
||||
|
|
2
deps/lld/ELF/OutputSections.cpp
vendored
2
deps/lld/ELF/OutputSections.cpp
vendored
|
@ -95,7 +95,7 @@ void OutputSection::addSection(InputSection *IS) {
|
|||
Flags = IS->Flags;
|
||||
} else {
|
||||
// Otherwise, check if new type or flags are compatible with existing ones.
|
||||
unsigned Mask = SHF_ALLOC | SHF_TLS | SHF_LINK_ORDER;
|
||||
unsigned Mask = SHF_TLS | SHF_LINK_ORDER;
|
||||
if ((Flags & Mask) != (IS->Flags & Mask))
|
||||
error("incompatible section flags for " + Name + "\n>>> " + toString(IS) +
|
||||
": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name +
|
||||
|
|
|
@ -8,7 +8,13 @@
|
|||
body{
|
||||
background-color:#111;
|
||||
color: #bbb;
|
||||
font-family: sans-serif;
|
||||
font-family: system-ui,
|
||||
/* Fallbacks for browsers that don't support system-ui */
|
||||
/* https://caniuse.com/#search=system-ui */
|
||||
-apple-system, /* iOS and macOS */
|
||||
Roboto, /* Android */
|
||||
"Segoe UI", /* Windows */
|
||||
sans-serif;
|
||||
}
|
||||
a {
|
||||
color: #88f;
|
||||
|
@ -4264,13 +4270,21 @@ fn foo() i32 {
|
|||
return 1234;
|
||||
}
|
||||
{#code_end#}
|
||||
<p>However, if the expression has type {#syntax#}void{#endsyntax#}:</p>
|
||||
<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>
|
||||
{#code_begin|test#}
|
||||
test "ignoring expression value" {
|
||||
foo();
|
||||
test "void is ignored" {
|
||||
returnsVoid();
|
||||
}
|
||||
|
||||
fn foo() void {}
|
||||
test "explicitly ignoring expression value" {
|
||||
_ = foo();
|
||||
}
|
||||
|
||||
fn returnsVoid() void {}
|
||||
|
||||
fn foo() i32 {
|
||||
return 1234;
|
||||
}
|
||||
{#code_end#}
|
||||
{#header_close#}
|
||||
|
||||
|
|
|
@ -24,15 +24,15 @@ pub fn main() !void {
|
|||
try stdout.print("\nGuess a number between 1 and 100: ");
|
||||
var line_buf: [20]u8 = undefined;
|
||||
|
||||
const line_len = io.readLine(line_buf[0..]) catch |err| switch (err) {
|
||||
error.InputTooLong => {
|
||||
const line = io.readLineSlice(line_buf[0..]) catch |err| switch (err) {
|
||||
error.OutOfMemory => {
|
||||
try stdout.print("Input too long.\n");
|
||||
continue;
|
||||
},
|
||||
error.EndOfFile, error.StdInUnavailable => return err,
|
||||
else => return err,
|
||||
};
|
||||
|
||||
const guess = fmt.parseUnsigned(u8, line_buf[0..line_len], 10) catch {
|
||||
const guess = fmt.parseUnsigned(u8, line, 10) catch {
|
||||
try stdout.print("Invalid number.\n");
|
||||
continue;
|
||||
};
|
||||
|
|
14
src/ir.cpp
14
src/ir.cpp
|
@ -67,6 +67,8 @@ enum ConstCastResultId {
|
|||
struct ConstCastOnly;
|
||||
struct ConstCastArg {
|
||||
size_t arg_index;
|
||||
ZigType *actual_param_type;
|
||||
ZigType *expected_param_type;
|
||||
ConstCastOnly *child;
|
||||
};
|
||||
|
||||
|
@ -8638,6 +8640,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
|
|||
if (arg_child.id != ConstCastResultIdOk) {
|
||||
result.id = ConstCastResultIdFnArg;
|
||||
result.data.fn_arg.arg_index = i;
|
||||
result.data.fn_arg.actual_param_type = actual_param_info->type;
|
||||
result.data.fn_arg.expected_param_type = expected_param_info->type;
|
||||
result.data.fn_arg.child = allocate_nonzero<ConstCastOnly>(1);
|
||||
*result.data.fn_arg.child = arg_child;
|
||||
return result;
|
||||
|
@ -10483,6 +10487,15 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
|
|||
}
|
||||
break;
|
||||
}
|
||||
case ConstCastResultIdFnArg: {
|
||||
ErrorMsg *msg = add_error_note(ira->codegen, parent_msg, source_node,
|
||||
buf_sprintf("parameter %" ZIG_PRI_usize ": '%s' cannot cast into '%s'",
|
||||
cast_result->data.fn_arg.arg_index,
|
||||
buf_ptr(&cast_result->data.fn_arg.actual_param_type->name),
|
||||
buf_ptr(&cast_result->data.fn_arg.expected_param_type->name)));
|
||||
report_recursive_error(ira, source_node, cast_result->data.fn_arg.child, msg);
|
||||
break;
|
||||
}
|
||||
case ConstCastResultIdFnAlign: // TODO
|
||||
case ConstCastResultIdFnCC: // TODO
|
||||
case ConstCastResultIdFnVarArgs: // TODO
|
||||
|
@ -10490,7 +10503,6 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa
|
|||
case ConstCastResultIdFnReturnType: // TODO
|
||||
case ConstCastResultIdFnArgCount: // TODO
|
||||
case ConstCastResultIdFnGenericArgCount: // TODO
|
||||
case ConstCastResultIdFnArg: // TODO
|
||||
case ConstCastResultIdFnArgNoAlias: // TODO
|
||||
case ConstCastResultIdUnresolvedInferredErrSet: // TODO
|
||||
case ConstCastResultIdAsyncAllocatorType: // TODO
|
||||
|
|
175
src/zig_llvm.cpp
175
src/zig_llvm.cpp
|
@ -681,18 +681,6 @@ void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {
|
|||
}
|
||||
|
||||
|
||||
static_assert((Triple::ArchType)ZigLLVM_LastArchType == Triple::LastArchType, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_LastVendorType == Triple::LastVendorType, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_LastOSType == Triple::LastOSType, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_LastEnvironmentType == Triple::LastEnvironmentType, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v5 == Triple::KalimbaSubArch_v5, "");
|
||||
|
||||
static_assert((Triple::ObjectFormatType)ZigLLVM_UnknownObjectFormat == Triple::UnknownObjectFormat, "");
|
||||
static_assert((Triple::ObjectFormatType)ZigLLVM_COFF == Triple::COFF, "");
|
||||
static_assert((Triple::ObjectFormatType)ZigLLVM_ELF == Triple::ELF, "");
|
||||
static_assert((Triple::ObjectFormatType)ZigLLVM_MachO == Triple::MachO, "");
|
||||
static_assert((Triple::ObjectFormatType)ZigLLVM_Wasm == Triple::Wasm, "");
|
||||
|
||||
const char *ZigLLVMGetArchTypeName(ZigLLVM_ArchType arch) {
|
||||
return (const char*)Triple::getArchTypeName((Triple::ArchType)arch).bytes_begin();
|
||||
}
|
||||
|
@ -919,3 +907,166 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_
|
|||
assert(false); // unreachable
|
||||
abort();
|
||||
}
|
||||
|
||||
static_assert((Triple::ArchType)ZigLLVM_UnknownArch == Triple::UnknownArch, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_arm == Triple::arm, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_armeb == Triple::armeb, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_aarch64 == Triple::aarch64, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_aarch64_be == Triple::aarch64_be, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_arc == Triple::arc, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_avr == Triple::avr, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_bpfel == Triple::bpfel, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_bpfeb == Triple::bpfeb, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_hexagon == Triple::hexagon, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_mips == Triple::mips, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_mipsel == Triple::mipsel, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_mips64 == Triple::mips64, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_mips64el == Triple::mips64el, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_msp430 == Triple::msp430, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_nios2 == Triple::nios2, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_ppc == Triple::ppc, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_ppc64 == Triple::ppc64, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_ppc64le == Triple::ppc64le, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_r600 == Triple::r600, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_amdgcn == Triple::amdgcn, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_riscv32 == Triple::riscv32, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_riscv64 == Triple::riscv64, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_sparc == Triple::sparc, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_sparcv9 == Triple::sparcv9, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_sparcel == Triple::sparcel, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_systemz == Triple::systemz, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_tce == Triple::tce, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_tcele == Triple::tcele, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_thumb == Triple::thumb, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_thumbeb == Triple::thumbeb, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_x86 == Triple::x86, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_x86_64 == Triple::x86_64, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_xcore == Triple::xcore, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_nvptx == Triple::nvptx, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_nvptx64 == Triple::nvptx64, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_le32 == Triple::le32, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_le64 == Triple::le64, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_amdil == Triple::amdil, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_amdil64 == Triple::amdil64, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_hsail == Triple::hsail, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_hsail64 == Triple::hsail64, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_spir == Triple::spir, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_spir64 == Triple::spir64, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_kalimba == Triple::kalimba, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_shave == Triple::shave, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_lanai == Triple::lanai, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_wasm32 == Triple::wasm32, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_wasm64 == Triple::wasm64, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_renderscript32 == Triple::renderscript32, "");
|
||||
static_assert((Triple::ArchType)ZigLLVM_renderscript64 == Triple::renderscript64, "");
|
||||
// Uncomment this when testing LLVM 8.0.0
|
||||
//static_assert((Triple::ArchType)ZigLLVM_LastArchType == Triple::LastArchType, "");
|
||||
|
||||
static_assert((Triple::SubArchType)ZigLLVM_NoSubArch == Triple::NoSubArch, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_4a == Triple::ARMSubArch_v8_4a, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_3a == Triple::ARMSubArch_v8_3a, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_2a == Triple::ARMSubArch_v8_2a, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_1a == Triple::ARMSubArch_v8_1a, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8 == Triple::ARMSubArch_v8, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8r == Triple::ARMSubArch_v8r, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8m_baseline == Triple::ARMSubArch_v8m_baseline, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8m_mainline == Triple::ARMSubArch_v8m_mainline, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7 == Triple::ARMSubArch_v7, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7em == Triple::ARMSubArch_v7em, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7m == Triple::ARMSubArch_v7m, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7s == Triple::ARMSubArch_v7s, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7k == Triple::ARMSubArch_v7k, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7ve == Triple::ARMSubArch_v7ve, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6 == Triple::ARMSubArch_v6, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6m == Triple::ARMSubArch_v6m, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6k == Triple::ARMSubArch_v6k, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6t2 == Triple::ARMSubArch_v6t2, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v5 == Triple::ARMSubArch_v5, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v5te == Triple::ARMSubArch_v5te, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v4t == Triple::ARMSubArch_v4t, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v3 == Triple::KalimbaSubArch_v3, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v4 == Triple::KalimbaSubArch_v4, "");
|
||||
static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v5 == Triple::KalimbaSubArch_v5, "");
|
||||
|
||||
static_assert((Triple::VendorType)ZigLLVM_UnknownVendor == Triple::UnknownVendor, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_Apple == Triple::Apple, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_PC == Triple::PC, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_SCEI == Triple::SCEI, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_BGP == Triple::BGP, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_BGQ == Triple::BGQ, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_Freescale == Triple::Freescale, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_IBM == Triple::IBM, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_ImaginationTechnologies == Triple::ImaginationTechnologies, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_MipsTechnologies == Triple::MipsTechnologies, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_NVIDIA == Triple::NVIDIA, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_CSR == Triple::CSR, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_Myriad == Triple::Myriad, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_AMD == Triple::AMD, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_Mesa == Triple::Mesa, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_SUSE == Triple::SUSE, "");
|
||||
static_assert((Triple::VendorType)ZigLLVM_OpenEmbedded == Triple::OpenEmbedded, "");
|
||||
// Uncomment this when testing LLVM 8.0.0
|
||||
//static_assert((Triple::VendorType)ZigLLVM_LastVendorType == Triple::LastVendorType, "");
|
||||
|
||||
static_assert((Triple::OSType)ZigLLVM_UnknownOS == Triple::UnknownOS, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_Ananas == Triple::Ananas, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_CloudABI == Triple::CloudABI, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_Darwin == Triple::Darwin, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_DragonFly == Triple::DragonFly, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_FreeBSD == Triple::FreeBSD, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_Fuchsia == Triple::Fuchsia, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_IOS == Triple::IOS, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_KFreeBSD == Triple::KFreeBSD, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_Linux == Triple::Linux, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_Lv2 == Triple::Lv2, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_MacOSX == Triple::MacOSX, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_NetBSD == Triple::NetBSD, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_OpenBSD == Triple::OpenBSD, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_Solaris == Triple::Solaris, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_Win32 == Triple::Win32, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_Haiku == Triple::Haiku, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_Minix == Triple::Minix, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_RTEMS == Triple::RTEMS, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_NaCl == Triple::NaCl, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_CNK == Triple::CNK, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_AIX == Triple::AIX, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_CUDA == Triple::CUDA, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_NVCL == Triple::NVCL, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_AMDHSA == Triple::AMDHSA, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_PS4 == Triple::PS4, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_ELFIAMCU == Triple::ELFIAMCU, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_TvOS == Triple::TvOS, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_WatchOS == Triple::WatchOS, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_Mesa3D == Triple::Mesa3D, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_Contiki == Triple::Contiki, "");
|
||||
static_assert((Triple::OSType)ZigLLVM_AMDPAL == Triple::AMDPAL, "");
|
||||
// Uncomment this when testing LLVM 8.0.0
|
||||
//static_assert((Triple::OSType)ZigLLVM_LastOSType == Triple::LastOSType, "");
|
||||
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_UnknownEnvironment == Triple::UnknownEnvironment, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_GNU == Triple::GNU, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_GNUABIN32 == Triple::GNUABIN32, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_GNUABI64 == Triple::GNUABI64, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_GNUEABI == Triple::GNUEABI, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_GNUEABIHF == Triple::GNUEABIHF, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_GNUX32 == Triple::GNUX32, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_CODE16 == Triple::CODE16, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_EABI == Triple::EABI, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_EABIHF == Triple::EABIHF, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_Android == Triple::Android, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_Musl == Triple::Musl, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_MuslEABI == Triple::MuslEABI, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_MuslEABIHF == Triple::MuslEABIHF, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_MSVC == Triple::MSVC, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_Itanium == Triple::Itanium, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_Cygnus == Triple::Cygnus, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_CoreCLR == Triple::CoreCLR, "");
|
||||
static_assert((Triple::EnvironmentType)ZigLLVM_Simulator == Triple::Simulator, "");
|
||||
// Uncomment this when testing LLVM 8.0.0
|
||||
//static_assert((Triple::EnvironmentType)ZigLLVM_LastEnvironmentType == Triple::LastEnvironmentType, "");
|
||||
|
||||
static_assert((Triple::ObjectFormatType)ZigLLVM_UnknownObjectFormat == Triple::UnknownObjectFormat, "");
|
||||
static_assert((Triple::ObjectFormatType)ZigLLVM_COFF == Triple::COFF, "");
|
||||
static_assert((Triple::ObjectFormatType)ZigLLVM_ELF == Triple::ELF, "");
|
||||
static_assert((Triple::ObjectFormatType)ZigLLVM_MachO == Triple::MachO, "");
|
||||
static_assert((Triple::ObjectFormatType)ZigLLVM_Wasm == Triple::Wasm, "");
|
||||
|
|
|
@ -150,7 +150,11 @@ pub const Builder = struct {
|
|||
}
|
||||
|
||||
pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
|
||||
return LibExeObjStep.createExecutable(self, name, root_src);
|
||||
return LibExeObjStep.createExecutable(self, name, root_src, false);
|
||||
}
|
||||
|
||||
pub fn addStaticExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
|
||||
return LibExeObjStep.createExecutable(self, name, root_src, true);
|
||||
}
|
||||
|
||||
pub fn addObject(self: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
|
||||
|
@ -807,6 +811,11 @@ pub const Target = union(enum) {
|
|||
}
|
||||
};
|
||||
|
||||
const Pkg = struct {
|
||||
name: []const u8,
|
||||
path: []const u8,
|
||||
};
|
||||
|
||||
pub const LibExeObjStep = struct {
|
||||
step: Step,
|
||||
builder: *Builder,
|
||||
|
@ -849,11 +858,6 @@ pub const LibExeObjStep = struct {
|
|||
source_files: ArrayList([]const u8),
|
||||
object_src: []const u8,
|
||||
|
||||
const Pkg = struct {
|
||||
name: []const u8,
|
||||
path: []const u8,
|
||||
};
|
||||
|
||||
const Kind = enum {
|
||||
Exe,
|
||||
Lib,
|
||||
|
@ -891,8 +895,8 @@ pub const LibExeObjStep = struct {
|
|||
return self;
|
||||
}
|
||||
|
||||
pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
|
||||
const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0))) catch unreachable;
|
||||
pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep {
|
||||
const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0))) catch unreachable;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -1270,6 +1274,9 @@ pub const LibExeObjStep = struct {
|
|||
zig_args.append("--ver-patch") catch unreachable;
|
||||
zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable;
|
||||
}
|
||||
if (self.kind == Kind.Exe and self.static) {
|
||||
zig_args.append("--static") catch unreachable;
|
||||
}
|
||||
|
||||
switch (self.target) {
|
||||
Target.Native => {},
|
||||
|
@ -1660,6 +1667,7 @@ pub const TestStep = struct {
|
|||
exec_cmd_args: ?[]const ?[]const u8,
|
||||
include_dirs: ArrayList([]const u8),
|
||||
lib_paths: ArrayList([]const u8),
|
||||
packages: ArrayList(Pkg),
|
||||
object_files: ArrayList([]const u8),
|
||||
no_rosegment: bool,
|
||||
output_path: ?[]const u8,
|
||||
|
@ -1680,6 +1688,7 @@ pub const TestStep = struct {
|
|||
.exec_cmd_args = null,
|
||||
.include_dirs = ArrayList([]const u8).init(builder.allocator),
|
||||
.lib_paths = ArrayList([]const u8).init(builder.allocator),
|
||||
.packages = ArrayList(Pkg).init(builder.allocator),
|
||||
.object_files = ArrayList([]const u8).init(builder.allocator),
|
||||
.no_rosegment = false,
|
||||
.output_path = null,
|
||||
|
@ -1695,6 +1704,13 @@ pub const TestStep = struct {
|
|||
self.lib_paths.append(path) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn addPackagePath(self: *TestStep, name: []const u8, pkg_index_path: []const u8) void {
|
||||
self.packages.append(Pkg{
|
||||
.name = name,
|
||||
.path = pkg_index_path,
|
||||
}) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn setVerbose(self: *TestStep, value: bool) void {
|
||||
self.verbose = value;
|
||||
}
|
||||
|
@ -1871,6 +1887,13 @@ pub const TestStep = struct {
|
|||
try zig_args.append(lib_path);
|
||||
}
|
||||
|
||||
for (self.packages.toSliceConst()) |pkg| {
|
||||
zig_args.append("--pkg-begin") catch unreachable;
|
||||
zig_args.append(pkg.name) catch unreachable;
|
||||
zig_args.append(builder.pathFromRoot(pkg.path)) catch unreachable;
|
||||
zig_args.append("--pkg-end") catch unreachable;
|
||||
}
|
||||
|
||||
if (self.no_rosegment) {
|
||||
try zig_args.append("--no-rosegment");
|
||||
}
|
||||
|
|
|
@ -198,49 +198,44 @@ pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var,
|
|||
}
|
||||
}
|
||||
|
||||
pub inline fn getReturnAddress(frame_count: usize) usize {
|
||||
var fp = @ptrToInt(@frameAddress());
|
||||
var i: usize = 0;
|
||||
while (fp != 0 and i < frame_count) {
|
||||
fp = @intToPtr(*const usize, fp).*;
|
||||
i += 1;
|
||||
pub const StackIterator = struct {
|
||||
first_addr: ?usize,
|
||||
fp: usize,
|
||||
|
||||
pub fn init(first_addr: ?usize) StackIterator {
|
||||
return StackIterator{
|
||||
.first_addr = first_addr,
|
||||
.fp = @ptrToInt(@frameAddress()),
|
||||
};
|
||||
}
|
||||
return @intToPtr(*const usize, fp + @sizeOf(usize)).*;
|
||||
}
|
||||
|
||||
fn next(self: *StackIterator) ?usize {
|
||||
if (self.fp == 0) return null;
|
||||
self.fp = @intToPtr(*const usize, self.fp).*;
|
||||
if (self.fp == 0) return null;
|
||||
|
||||
if (self.first_addr) |addr| {
|
||||
while (self.fp != 0) : (self.fp = @intToPtr(*const usize, self.fp).*) {
|
||||
const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
|
||||
if (addr == return_address) {
|
||||
self.first_addr = null;
|
||||
return return_address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
|
||||
return return_address;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
|
||||
switch (builtin.os) {
|
||||
builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),
|
||||
else => {},
|
||||
}
|
||||
const AddressState = union(enum) {
|
||||
NotLookingForStartAddress,
|
||||
LookingForStartAddress: usize,
|
||||
};
|
||||
// TODO: I want to express like this:
|
||||
//var addr_state = if (start_addr) |addr| AddressState { .LookingForStartAddress = addr }
|
||||
// else AddressState.NotLookingForStartAddress;
|
||||
var addr_state: AddressState = undefined;
|
||||
if (start_addr) |addr| {
|
||||
addr_state = AddressState{ .LookingForStartAddress = addr };
|
||||
} else {
|
||||
addr_state = AddressState.NotLookingForStartAddress;
|
||||
}
|
||||
|
||||
var fp = @ptrToInt(@frameAddress());
|
||||
while (fp != 0) : (fp = @intToPtr(*const usize, fp).*) {
|
||||
const return_address = @intToPtr(*const usize, fp + @sizeOf(usize)).*;
|
||||
|
||||
switch (addr_state) {
|
||||
AddressState.NotLookingForStartAddress => {},
|
||||
AddressState.LookingForStartAddress => |addr| {
|
||||
if (return_address == addr) {
|
||||
addr_state = AddressState.NotLookingForStartAddress;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
},
|
||||
}
|
||||
var it = StackIterator.init(start_addr);
|
||||
while (it.next()) |return_address| {
|
||||
try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
|
||||
}
|
||||
}
|
||||
|
@ -284,7 +279,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
|
|||
const mod_index = for (di.sect_contribs) |sect_contrib| {
|
||||
if (sect_contrib.Section > di.coff.sections.len) continue;
|
||||
// Remember that SectionContribEntry.Section is 1-based.
|
||||
coff_section = &di.coff.sections.toSlice()[sect_contrib.Section-1];
|
||||
coff_section = &di.coff.sections.toSlice()[sect_contrib.Section - 1];
|
||||
|
||||
const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
|
||||
const vaddr_end = vaddr_start + sect_contrib.Size;
|
||||
|
@ -414,7 +409,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
|
|||
|
||||
if (opt_line_info) |line_info| {
|
||||
try out_stream.print("\n");
|
||||
if (printLineFromFile(out_stream, line_info)) {
|
||||
if (printLineFromFileAnyOs(out_stream, line_info)) {
|
||||
if (line_info.column == 0) {
|
||||
try out_stream.write("\n");
|
||||
} else {
|
||||
|
@ -598,7 +593,15 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
|
|||
} else "???";
|
||||
if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| {
|
||||
defer line_info.deinit();
|
||||
try printLineInfo(di, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color);
|
||||
try printLineInfo(
|
||||
out_stream,
|
||||
line_info,
|
||||
address,
|
||||
symbol_name,
|
||||
compile_unit_name,
|
||||
tty_color,
|
||||
printLineFromFileAnyOs,
|
||||
);
|
||||
} else |err| switch (err) {
|
||||
error.MissingDebugInfo, error.InvalidDebugInfo => {
|
||||
if (tty_color) {
|
||||
|
@ -611,7 +614,15 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
|
|||
}
|
||||
}
|
||||
|
||||
pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
|
||||
/// This function works in freestanding mode.
|
||||
/// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
|
||||
pub fn printSourceAtAddressDwarf(
|
||||
debug_info: *DwarfInfo,
|
||||
out_stream: var,
|
||||
address: usize,
|
||||
tty_color: bool,
|
||||
comptime printLineFromFile: var,
|
||||
) !void {
|
||||
const compile_unit = findCompileUnit(debug_info, address) catch {
|
||||
if (tty_color) {
|
||||
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
|
|||
return;
|
||||
};
|
||||
const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
|
||||
if (getLineNumberInfoLinux(debug_info, compile_unit, address - 1)) |line_info| {
|
||||
if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| {
|
||||
defer line_info.deinit();
|
||||
const symbol_name = "???";
|
||||
try printLineInfo(debug_info, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color);
|
||||
try printLineInfo(
|
||||
out_stream,
|
||||
line_info,
|
||||
address,
|
||||
symbol_name,
|
||||
compile_unit_name,
|
||||
tty_color,
|
||||
printLineFromFile,
|
||||
);
|
||||
} else |err| switch (err) {
|
||||
error.MissingDebugInfo, error.InvalidDebugInfo => {
|
||||
if (tty_color) {
|
||||
|
@ -637,14 +656,18 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres
|
|||
}
|
||||
}
|
||||
|
||||
pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
|
||||
return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs);
|
||||
}
|
||||
|
||||
fn printLineInfo(
|
||||
debug_info: *DebugInfo,
|
||||
out_stream: var,
|
||||
line_info: LineInfo,
|
||||
address: usize,
|
||||
symbol_name: []const u8,
|
||||
compile_unit_name: []const u8,
|
||||
tty_color: bool,
|
||||
comptime printLineFromFile: var,
|
||||
) !void {
|
||||
if (tty_color) {
|
||||
try out_stream.print(
|
||||
|
@ -872,55 +895,68 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
|
|||
return list.toOwnedSlice();
|
||||
}
|
||||
|
||||
fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
|
||||
var di = DebugInfo{
|
||||
.self_exe_file = undefined,
|
||||
.elf = undefined,
|
||||
.debug_info = undefined,
|
||||
.debug_abbrev = undefined,
|
||||
.debug_str = undefined,
|
||||
.debug_line = undefined,
|
||||
.debug_ranges = null,
|
||||
.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
|
||||
.compile_unit_list = ArrayList(CompileUnit).init(allocator),
|
||||
fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section {
|
||||
const elf_header = (try elf_file.findSection(name)) orelse return null;
|
||||
return DwarfInfo.Section{
|
||||
.offset = elf_header.offset,
|
||||
.size = elf_header.size,
|
||||
};
|
||||
di.self_exe_file = try os.openSelfExe();
|
||||
errdefer di.self_exe_file.close();
|
||||
}
|
||||
|
||||
try di.elf.openFile(allocator, di.self_exe_file);
|
||||
errdefer di.elf.close();
|
||||
/// Initialize DWARF info. The caller has the responsibility to initialize most
|
||||
/// the DwarfInfo fields before calling. These fields can be left undefined:
|
||||
/// * abbrev_table_list
|
||||
/// * compile_unit_list
|
||||
pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
|
||||
di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
|
||||
di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
|
||||
try scanAllCompileUnits(di);
|
||||
}
|
||||
|
||||
di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;
|
||||
di.debug_abbrev = (try di.elf.findSection(".debug_abbrev")) orelse return error.MissingDebugInfo;
|
||||
di.debug_str = (try di.elf.findSection(".debug_str")) orelse return error.MissingDebugInfo;
|
||||
di.debug_line = (try di.elf.findSection(".debug_line")) orelse return error.MissingDebugInfo;
|
||||
di.debug_ranges = (try di.elf.findSection(".debug_ranges"));
|
||||
try scanAllCompileUnits(&di);
|
||||
pub fn openElfDebugInfo(
|
||||
allocator: *mem.Allocator,
|
||||
elf_seekable_stream: *DwarfSeekableStream,
|
||||
elf_in_stream: *DwarfInStream,
|
||||
) !DwarfInfo {
|
||||
var efile: elf.Elf = undefined;
|
||||
try efile.openStream(allocator, elf_seekable_stream, elf_in_stream);
|
||||
errdefer efile.close();
|
||||
|
||||
var di = DwarfInfo{
|
||||
.dwarf_seekable_stream = elf_seekable_stream,
|
||||
.dwarf_in_stream = elf_in_stream,
|
||||
.endian = efile.endian,
|
||||
.debug_info = (try findDwarfSectionFromElf(&efile, ".debug_info")) orelse return error.MissingDebugInfo,
|
||||
.debug_abbrev = (try findDwarfSectionFromElf(&efile, ".debug_abbrev")) orelse return error.MissingDebugInfo,
|
||||
.debug_str = (try findDwarfSectionFromElf(&efile, ".debug_str")) orelse return error.MissingDebugInfo,
|
||||
.debug_line = (try findDwarfSectionFromElf(&efile, ".debug_line")) orelse return error.MissingDebugInfo,
|
||||
.debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")),
|
||||
.abbrev_table_list = undefined,
|
||||
.compile_unit_list = undefined,
|
||||
};
|
||||
try openDwarfDebugInfo(&di, allocator);
|
||||
return di;
|
||||
}
|
||||
|
||||
pub fn findElfSection(elf: *Elf, name: []const u8) ?*elf.Shdr {
|
||||
var file_stream = elf.in_file.inStream();
|
||||
const in = &file_stream.stream;
|
||||
fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo {
|
||||
const S = struct {
|
||||
var self_exe_file: os.File = undefined;
|
||||
var self_exe_seekable_stream: os.File.SeekableStream = undefined;
|
||||
var self_exe_in_stream: os.File.InStream = undefined;
|
||||
};
|
||||
S.self_exe_file = try os.openSelfExe();
|
||||
errdefer S.self_exe_file.close();
|
||||
|
||||
section_loop: for (elf.section_headers) |*elf_section| {
|
||||
if (elf_section.sh_type == SHT_NULL) continue;
|
||||
S.self_exe_seekable_stream = S.self_exe_file.seekableStream();
|
||||
S.self_exe_in_stream = S.self_exe_file.inStream();
|
||||
|
||||
const name_offset = elf.string_section.offset + elf_section.name;
|
||||
try elf.in_file.seekTo(name_offset);
|
||||
|
||||
for (name) |expected_c| {
|
||||
const target_c = try in.readByte();
|
||||
if (target_c == 0 or expected_c != target_c) continue :section_loop;
|
||||
}
|
||||
|
||||
{
|
||||
const null_byte = try in.readByte();
|
||||
if (null_byte == 0) return elf_section;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return openElfDebugInfo(
|
||||
allocator,
|
||||
// TODO https://github.com/ziglang/zig/issues/764
|
||||
@ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream),
|
||||
// TODO https://github.com/ziglang/zig/issues/764
|
||||
@ptrCast(*DwarfInStream, &S.self_exe_in_stream.stream),
|
||||
);
|
||||
}
|
||||
|
||||
fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
|
||||
|
@ -1000,7 +1036,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
|
|||
};
|
||||
}
|
||||
|
||||
fn printLineFromFile(out_stream: var, line_info: LineInfo) !void {
|
||||
fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
|
||||
var f = try os.File.openRead(line_info.file_name);
|
||||
defer f.close();
|
||||
// TODO fstat and make sure that the file has the correct size
|
||||
|
@ -1053,6 +1089,35 @@ const MachOFile = struct {
|
|||
sect_debug_line: ?*const macho.section_64,
|
||||
};
|
||||
|
||||
pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
|
||||
pub const DwarfInStream = io.InStream(anyerror);
|
||||
|
||||
pub const DwarfInfo = struct {
|
||||
dwarf_seekable_stream: *DwarfSeekableStream,
|
||||
dwarf_in_stream: *DwarfInStream,
|
||||
endian: builtin.Endian,
|
||||
debug_info: Section,
|
||||
debug_abbrev: Section,
|
||||
debug_str: Section,
|
||||
debug_line: Section,
|
||||
debug_ranges: ?Section,
|
||||
abbrev_table_list: ArrayList(AbbrevTableHeader),
|
||||
compile_unit_list: ArrayList(CompileUnit),
|
||||
|
||||
pub const Section = struct {
|
||||
offset: usize,
|
||||
size: usize,
|
||||
};
|
||||
|
||||
pub fn allocator(self: DwarfInfo) *mem.Allocator {
|
||||
return self.abbrev_table_list.allocator;
|
||||
}
|
||||
|
||||
pub fn readString(self: *DwarfInfo) ![]u8 {
|
||||
return readStringRaw(self.allocator(), self.dwarf_in_stream);
|
||||
}
|
||||
};
|
||||
|
||||
pub const DebugInfo = switch (builtin.os) {
|
||||
builtin.Os.macosx => struct {
|
||||
symbols: []const MachoSymbol,
|
||||
|
@ -1076,32 +1141,7 @@ pub const DebugInfo = switch (builtin.os) {
|
|||
sect_contribs: []pdb.SectionContribEntry,
|
||||
modules: []Module,
|
||||
},
|
||||
builtin.Os.linux => struct {
|
||||
self_exe_file: os.File,
|
||||
elf: elf.Elf,
|
||||
debug_info: *elf.SectionHeader,
|
||||
debug_abbrev: *elf.SectionHeader,
|
||||
debug_str: *elf.SectionHeader,
|
||||
debug_line: *elf.SectionHeader,
|
||||
debug_ranges: ?*elf.SectionHeader,
|
||||
abbrev_table_list: ArrayList(AbbrevTableHeader),
|
||||
compile_unit_list: ArrayList(CompileUnit),
|
||||
|
||||
pub fn allocator(self: DebugInfo) *mem.Allocator {
|
||||
return self.abbrev_table_list.allocator;
|
||||
}
|
||||
|
||||
pub fn readString(self: *DebugInfo) ![]u8 {
|
||||
var in_file_stream = self.self_exe_file.inStream();
|
||||
const in_stream = &in_file_stream.stream;
|
||||
return readStringRaw(self.allocator(), in_stream);
|
||||
}
|
||||
|
||||
pub fn close(self: *DebugInfo) void {
|
||||
self.self_exe_file.close();
|
||||
self.elf.close();
|
||||
}
|
||||
},
|
||||
builtin.Os.linux => DwarfInfo,
|
||||
builtin.Os.freebsd => struct {},
|
||||
else => @compileError("Unsupported OS"),
|
||||
};
|
||||
|
@ -1206,11 +1246,11 @@ const Die = struct {
|
|||
};
|
||||
}
|
||||
|
||||
fn getAttrString(self: *const Die, st: *DebugInfo, id: u64) ![]u8 {
|
||||
fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
|
||||
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
|
||||
return switch (form_value.*) {
|
||||
FormValue.String => |value| value,
|
||||
FormValue.StrPtr => |offset| getString(st, offset),
|
||||
FormValue.StrPtr => |offset| getString(di, offset),
|
||||
else => error.InvalidDebugInfo,
|
||||
};
|
||||
}
|
||||
|
@ -1223,14 +1263,15 @@ const FileEntry = struct {
|
|||
len_bytes: usize,
|
||||
};
|
||||
|
||||
const LineInfo = struct {
|
||||
pub const LineInfo = struct {
|
||||
line: usize,
|
||||
column: usize,
|
||||
file_name: []u8,
|
||||
allocator: *mem.Allocator,
|
||||
file_name: []const u8,
|
||||
allocator: ?*mem.Allocator,
|
||||
|
||||
fn deinit(self: *const LineInfo) void {
|
||||
self.allocator.free(self.file_name);
|
||||
fn deinit(self: LineInfo) void {
|
||||
const allocator = self.allocator orelse return;
|
||||
allocator.free(self.file_name);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1321,10 +1362,10 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
|
|||
return buf.toSlice();
|
||||
}
|
||||
|
||||
fn getString(st: *DebugInfo, offset: u64) ![]u8 {
|
||||
const pos = st.debug_str.offset + offset;
|
||||
try st.self_exe_file.seekTo(pos);
|
||||
return st.readString();
|
||||
fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
|
||||
const pos = di.debug_str.offset + offset;
|
||||
try di.dwarf_seekable_stream.seekTo(pos);
|
||||
return di.readString();
|
||||
}
|
||||
|
||||
fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
|
||||
|
@ -1371,14 +1412,7 @@ fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type
|
|||
return parseFormValueRefLen(allocator, in_stream, block_len);
|
||||
}
|
||||
|
||||
const ParseFormValueError = error{
|
||||
EndOfStream,
|
||||
InvalidDebugInfo,
|
||||
EndOfFile,
|
||||
OutOfMemory,
|
||||
} || std.os.File.ReadError;
|
||||
|
||||
fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) ParseFormValueError!FormValue {
|
||||
fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
|
||||
return switch (form_id) {
|
||||
DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
|
||||
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
|
|||
};
|
||||
}
|
||||
|
||||
fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {
|
||||
const in_file = st.self_exe_file;
|
||||
var in_file_stream = in_file.inStream();
|
||||
const in_stream = &in_file_stream.stream;
|
||||
var result = AbbrevTable.init(st.allocator());
|
||||
fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
|
||||
var result = AbbrevTable.init(di.allocator());
|
||||
while (true) {
|
||||
const abbrev_code = try readULeb128(in_stream);
|
||||
const abbrev_code = try readULeb128(di.dwarf_in_stream);
|
||||
if (abbrev_code == 0) return result;
|
||||
try result.append(AbbrevTableEntry{
|
||||
.abbrev_code = abbrev_code,
|
||||
.tag_id = try readULeb128(in_stream),
|
||||
.has_children = (try in_stream.readByte()) == DW.CHILDREN_yes,
|
||||
.attrs = ArrayList(AbbrevAttr).init(st.allocator()),
|
||||
.tag_id = try readULeb128(di.dwarf_in_stream),
|
||||
.has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
|
||||
.attrs = ArrayList(AbbrevAttr).init(di.allocator()),
|
||||
});
|
||||
const attrs = &result.items[result.len - 1].attrs;
|
||||
|
||||
while (true) {
|
||||
const attr_id = try readULeb128(in_stream);
|
||||
const form_id = try readULeb128(in_stream);
|
||||
const attr_id = try readULeb128(di.dwarf_in_stream);
|
||||
const form_id = try readULeb128(di.dwarf_in_stream);
|
||||
if (attr_id == 0 and form_id == 0) break;
|
||||
try attrs.append(AbbrevAttr{
|
||||
.attr_id = attr_id,
|
||||
|
@ -1458,18 +1489,18 @@ fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {
|
|||
|
||||
/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
|
||||
/// seeks in the stream and parses it.
|
||||
fn getAbbrevTable(st: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable {
|
||||
for (st.abbrev_table_list.toSlice()) |*header| {
|
||||
fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
|
||||
for (di.abbrev_table_list.toSlice()) |*header| {
|
||||
if (header.offset == abbrev_offset) {
|
||||
return &header.table;
|
||||
}
|
||||
}
|
||||
try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
|
||||
try st.abbrev_table_list.append(AbbrevTableHeader{
|
||||
try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset);
|
||||
try di.abbrev_table_list.append(AbbrevTableHeader{
|
||||
.offset = abbrev_offset,
|
||||
.table = try parseAbbrevTable(st),
|
||||
.table = try parseAbbrevTable(di),
|
||||
});
|
||||
return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table;
|
||||
return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
|
||||
}
|
||||
|
||||
fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
|
||||
|
@ -1479,23 +1510,20 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
|
|||
return null;
|
||||
}
|
||||
|
||||
fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
|
||||
const in_file = st.self_exe_file;
|
||||
var in_file_stream = in_file.inStream();
|
||||
const in_stream = &in_file_stream.stream;
|
||||
const abbrev_code = try readULeb128(in_stream);
|
||||
fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
|
||||
const abbrev_code = try readULeb128(di.dwarf_in_stream);
|
||||
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
|
||||
|
||||
var result = Die{
|
||||
.tag_id = table_entry.tag_id,
|
||||
.has_children = table_entry.has_children,
|
||||
.attrs = ArrayList(Die.Attr).init(st.allocator()),
|
||||
.attrs = ArrayList(Die.Attr).init(di.allocator()),
|
||||
};
|
||||
try result.attrs.resize(table_entry.attrs.len);
|
||||
for (table_entry.attrs.toSliceConst()) |attr, i| {
|
||||
result.attrs.items[i] = Die.Attr{
|
||||
.id = attr.attr_id,
|
||||
.value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
|
||||
.value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
|
||||
};
|
||||
}
|
||||
return result;
|
||||
|
@ -1699,22 +1727,18 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
|
|||
return error.MissingDebugInfo;
|
||||
}
|
||||
|
||||
fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo {
|
||||
fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
|
||||
const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
|
||||
|
||||
const in_file = di.self_exe_file;
|
||||
const debug_line_end = di.debug_line.offset + di.debug_line.size;
|
||||
var this_offset = di.debug_line.offset;
|
||||
var this_index: usize = 0;
|
||||
|
||||
var in_file_stream = in_file.inStream();
|
||||
const in_stream = &in_file_stream.stream;
|
||||
|
||||
while (this_offset < debug_line_end) : (this_index += 1) {
|
||||
try in_file.seekTo(this_offset);
|
||||
try di.dwarf_seekable_stream.seekTo(this_offset);
|
||||
|
||||
var is_64: bool = undefined;
|
||||
const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
|
||||
const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
|
||||
if (unit_length == 0) return error.MissingDebugInfo;
|
||||
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
|
||||
|
||||
|
@ -1723,35 +1747,35 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
|
|||
continue;
|
||||
}
|
||||
|
||||
const version = try in_stream.readInt(di.elf.endian, u16);
|
||||
const version = try di.dwarf_in_stream.readInt(di.endian, u16);
|
||||
// TODO support 3 and 5
|
||||
if (version != 2 and version != 4) return error.InvalidDebugInfo;
|
||||
|
||||
const prologue_length = if (is_64) try in_stream.readInt(di.elf.endian, u64) else try in_stream.readInt(di.elf.endian, u32);
|
||||
const prog_start_offset = (try in_file.getPos()) + prologue_length;
|
||||
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);
|
||||
const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
|
||||
|
||||
const minimum_instruction_length = try in_stream.readByte();
|
||||
const minimum_instruction_length = try di.dwarf_in_stream.readByte();
|
||||
if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
|
||||
|
||||
if (version >= 4) {
|
||||
// maximum_operations_per_instruction
|
||||
_ = try in_stream.readByte();
|
||||
_ = try di.dwarf_in_stream.readByte();
|
||||
}
|
||||
|
||||
const default_is_stmt = (try in_stream.readByte()) != 0;
|
||||
const line_base = try in_stream.readByteSigned();
|
||||
const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
|
||||
const line_base = try di.dwarf_in_stream.readByteSigned();
|
||||
|
||||
const line_range = try in_stream.readByte();
|
||||
const line_range = try di.dwarf_in_stream.readByte();
|
||||
if (line_range == 0) return error.InvalidDebugInfo;
|
||||
|
||||
const opcode_base = try in_stream.readByte();
|
||||
const opcode_base = try di.dwarf_in_stream.readByte();
|
||||
|
||||
const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
|
||||
|
||||
{
|
||||
var i: usize = 0;
|
||||
while (i < opcode_base - 1) : (i += 1) {
|
||||
standard_opcode_lengths[i] = try in_stream.readByte();
|
||||
standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1769,9 +1793,9 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
|
|||
while (true) {
|
||||
const file_name = try di.readString();
|
||||
if (file_name.len == 0) break;
|
||||
const dir_index = try readULeb128(in_stream);
|
||||
const mtime = try readULeb128(in_stream);
|
||||
const len_bytes = try readULeb128(in_stream);
|
||||
const dir_index = try readULeb128(di.dwarf_in_stream);
|
||||
const mtime = try readULeb128(di.dwarf_in_stream);
|
||||
const len_bytes = try readULeb128(di.dwarf_in_stream);
|
||||
try file_entries.append(FileEntry{
|
||||
.file_name = file_name,
|
||||
.dir_index = dir_index,
|
||||
|
@ -1780,15 +1804,15 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
|
|||
});
|
||||
}
|
||||
|
||||
try in_file.seekTo(prog_start_offset);
|
||||
try di.dwarf_seekable_stream.seekTo(prog_start_offset);
|
||||
|
||||
while (true) {
|
||||
const opcode = try in_stream.readByte();
|
||||
const opcode = try di.dwarf_in_stream.readByte();
|
||||
|
||||
if (opcode == DW.LNS_extended_op) {
|
||||
const op_size = try readULeb128(in_stream);
|
||||
const op_size = try readULeb128(di.dwarf_in_stream);
|
||||
if (op_size < 1) return error.InvalidDebugInfo;
|
||||
var sub_op = try in_stream.readByte();
|
||||
var sub_op = try di.dwarf_in_stream.readByte();
|
||||
switch (sub_op) {
|
||||
DW.LNE_end_sequence => {
|
||||
prog.end_sequence = true;
|
||||
|
@ -1796,14 +1820,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
|
|||
return error.MissingDebugInfo;
|
||||
},
|
||||
DW.LNE_set_address => {
|
||||
const addr = try in_stream.readInt(di.elf.endian, usize);
|
||||
const addr = try di.dwarf_in_stream.readInt(di.endian, usize);
|
||||
prog.address = addr;
|
||||
},
|
||||
DW.LNE_define_file => {
|
||||
const file_name = try di.readString();
|
||||
const dir_index = try readULeb128(in_stream);
|
||||
const mtime = try readULeb128(in_stream);
|
||||
const len_bytes = try readULeb128(in_stream);
|
||||
const dir_index = try readULeb128(di.dwarf_in_stream);
|
||||
const mtime = try readULeb128(di.dwarf_in_stream);
|
||||
const len_bytes = try readULeb128(di.dwarf_in_stream);
|
||||
try file_entries.append(FileEntry{
|
||||
.file_name = file_name,
|
||||
.dir_index = dir_index,
|
||||
|
@ -1813,7 +1837,7 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
|
|||
},
|
||||
else => {
|
||||
const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
|
||||
try in_file.seekForward(fwd_amt);
|
||||
try di.dwarf_seekable_stream.seekForward(fwd_amt);
|
||||
},
|
||||
}
|
||||
} else if (opcode >= opcode_base) {
|
||||
|
@ -1832,19 +1856,19 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
|
|||
prog.basic_block = false;
|
||||
},
|
||||
DW.LNS_advance_pc => {
|
||||
const arg = try readULeb128(in_stream);
|
||||
const arg = try readULeb128(di.dwarf_in_stream);
|
||||
prog.address += arg * minimum_instruction_length;
|
||||
},
|
||||
DW.LNS_advance_line => {
|
||||
const arg = try readILeb128(in_stream);
|
||||
const arg = try readILeb128(di.dwarf_in_stream);
|
||||
prog.line += arg;
|
||||
},
|
||||
DW.LNS_set_file => {
|
||||
const arg = try readULeb128(in_stream);
|
||||
const arg = try readULeb128(di.dwarf_in_stream);
|
||||
prog.file = arg;
|
||||
},
|
||||
DW.LNS_set_column => {
|
||||
const arg = try readULeb128(in_stream);
|
||||
const arg = try readULeb128(di.dwarf_in_stream);
|
||||
prog.column = arg;
|
||||
},
|
||||
DW.LNS_negate_stmt => {
|
||||
|
@ -1858,14 +1882,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
|
|||
prog.address += inc_addr;
|
||||
},
|
||||
DW.LNS_fixed_advance_pc => {
|
||||
const arg = try in_stream.readInt(di.elf.endian, u16);
|
||||
const arg = try di.dwarf_in_stream.readInt(di.endian, u16);
|
||||
prog.address += arg;
|
||||
},
|
||||
DW.LNS_set_prologue_end => {},
|
||||
else => {
|
||||
if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
|
||||
const len_bytes = standard_opcode_lengths[opcode - 1];
|
||||
try in_file.seekForward(len_bytes);
|
||||
try di.dwarf_seekable_stream.seekForward(len_bytes);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1877,36 +1901,33 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
|
|||
return error.MissingDebugInfo;
|
||||
}
|
||||
|
||||
fn scanAllCompileUnits(st: *DebugInfo) !void {
|
||||
const debug_info_end = st.debug_info.offset + st.debug_info.size;
|
||||
var this_unit_offset = st.debug_info.offset;
|
||||
fn scanAllCompileUnits(di: *DwarfInfo) !void {
|
||||
const debug_info_end = di.debug_info.offset + di.debug_info.size;
|
||||
var this_unit_offset = di.debug_info.offset;
|
||||
var cu_index: usize = 0;
|
||||
|
||||
var in_file_stream = st.self_exe_file.inStream();
|
||||
const in_stream = &in_file_stream.stream;
|
||||
|
||||
while (this_unit_offset < debug_info_end) {
|
||||
try st.self_exe_file.seekTo(this_unit_offset);
|
||||
try di.dwarf_seekable_stream.seekTo(this_unit_offset);
|
||||
|
||||
var is_64: bool = undefined;
|
||||
const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
|
||||
const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
|
||||
if (unit_length == 0) return;
|
||||
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
|
||||
|
||||
const version = try in_stream.readInt(st.elf.endian, u16);
|
||||
const version = try di.dwarf_in_stream.readInt(di.endian, u16);
|
||||
if (version < 2 or version > 5) return error.InvalidDebugInfo;
|
||||
|
||||
const debug_abbrev_offset = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
|
||||
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);
|
||||
|
||||
const address_size = try in_stream.readByte();
|
||||
const address_size = try di.dwarf_in_stream.readByte();
|
||||
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
|
||||
|
||||
const compile_unit_pos = try st.self_exe_file.getPos();
|
||||
const abbrev_table = try getAbbrevTable(st, debug_abbrev_offset);
|
||||
const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
|
||||
const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
|
||||
|
||||
try st.self_exe_file.seekTo(compile_unit_pos);
|
||||
try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
|
||||
|
||||
const compile_unit_die = try st.allocator().create(try parseDie(st, abbrev_table, is_64));
|
||||
const compile_unit_die = try di.allocator().create(try parseDie(di, abbrev_table, is_64));
|
||||
|
||||
if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
|
||||
|
||||
|
@ -1934,7 +1955,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
|
|||
}
|
||||
};
|
||||
|
||||
try st.compile_unit_list.append(CompileUnit{
|
||||
try di.compile_unit_list.append(CompileUnit{
|
||||
.version = version,
|
||||
.is_64 = is_64,
|
||||
.pc_range = pc_range,
|
||||
|
@ -1947,20 +1968,18 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
|
|||
}
|
||||
}
|
||||
|
||||
fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit {
|
||||
var in_file_stream = st.self_exe_file.inStream();
|
||||
const in_stream = &in_file_stream.stream;
|
||||
for (st.compile_unit_list.toSlice()) |*compile_unit| {
|
||||
fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
|
||||
for (di.compile_unit_list.toSlice()) |*compile_unit| {
|
||||
if (compile_unit.pc_range) |range| {
|
||||
if (target_address >= range.start and target_address < range.end) return compile_unit;
|
||||
}
|
||||
if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
|
||||
var base_address: usize = 0;
|
||||
if (st.debug_ranges) |debug_ranges| {
|
||||
try st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset);
|
||||
if (di.debug_ranges) |debug_ranges| {
|
||||
try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
|
||||
while (true) {
|
||||
const begin_addr = try in_stream.readIntLe(usize);
|
||||
const end_addr = try in_stream.readIntLe(usize);
|
||||
const begin_addr = try di.dwarf_in_stream.readIntLe(usize);
|
||||
const end_addr = try di.dwarf_in_stream.readIntLe(usize);
|
||||
if (begin_addr == 0 and end_addr == 0) {
|
||||
break;
|
||||
}
|
||||
|
|
45
std/elf.zig
45
std/elf.zig
|
@ -353,7 +353,8 @@ pub const SectionHeader = struct {
|
|||
};
|
||||
|
||||
pub const Elf = struct {
|
||||
in_file: os.File,
|
||||
seekable_stream: *io.SeekableStream(anyerror, anyerror),
|
||||
in_stream: *io.InStream(anyerror),
|
||||
auto_close_stream: bool,
|
||||
is_64: bool,
|
||||
endian: builtin.Endian,
|
||||
|
@ -370,19 +371,24 @@ pub const Elf = struct {
|
|||
|
||||
/// Call close when done.
|
||||
pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void {
|
||||
try elf.prealloc_file.open(path);
|
||||
try elf.openFile(allocator, *elf.prealloc_file);
|
||||
elf.auto_close_stream = true;
|
||||
@compileError("TODO implement");
|
||||
}
|
||||
|
||||
/// Call close when done.
|
||||
pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: os.File) !void {
|
||||
elf.allocator = allocator;
|
||||
elf.in_file = file;
|
||||
elf.auto_close_stream = false;
|
||||
@compileError("TODO implement");
|
||||
}
|
||||
|
||||
var file_stream = elf.in_file.inStream();
|
||||
const in = &file_stream.stream;
|
||||
pub fn openStream(
|
||||
elf: *Elf,
|
||||
allocator: *mem.Allocator,
|
||||
seekable_stream: *io.SeekableStream(anyerror, anyerror),
|
||||
in: *io.InStream(anyerror),
|
||||
) !void {
|
||||
elf.auto_close_stream = false;
|
||||
elf.allocator = allocator;
|
||||
elf.seekable_stream = seekable_stream;
|
||||
elf.in_stream = in;
|
||||
|
||||
var magic: [4]u8 = undefined;
|
||||
try in.readNoEof(magic[0..]);
|
||||
|
@ -404,7 +410,7 @@ pub const Elf = struct {
|
|||
if (version_byte != 1) return error.InvalidFormat;
|
||||
|
||||
// skip over padding
|
||||
try elf.in_file.seekForward(9);
|
||||
try seekable_stream.seekForward(9);
|
||||
|
||||
elf.file_type = switch (try in.readInt(elf.endian, u16)) {
|
||||
1 => FileType.Relocatable,
|
||||
|
@ -441,7 +447,7 @@ pub const Elf = struct {
|
|||
}
|
||||
|
||||
// skip over flags
|
||||
try elf.in_file.seekForward(4);
|
||||
try seekable_stream.seekForward(4);
|
||||
|
||||
const header_size = try in.readInt(elf.endian, u16);
|
||||
if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) {
|
||||
|
@ -461,12 +467,12 @@ pub const Elf = struct {
|
|||
const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count);
|
||||
const end_ph = try math.add(u64, elf.program_header_offset, ph_byte_count);
|
||||
|
||||
const stream_end = try elf.in_file.getEndPos();
|
||||
const stream_end = try seekable_stream.getEndPos();
|
||||
if (stream_end < end_sh or stream_end < end_ph) {
|
||||
return error.InvalidFormat;
|
||||
}
|
||||
|
||||
try elf.in_file.seekTo(elf.section_header_offset);
|
||||
try seekable_stream.seekTo(elf.section_header_offset);
|
||||
|
||||
elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count);
|
||||
errdefer elf.allocator.free(elf.section_headers);
|
||||
|
@ -521,26 +527,23 @@ pub const Elf = struct {
|
|||
pub fn close(elf: *Elf) void {
|
||||
elf.allocator.free(elf.section_headers);
|
||||
|
||||
if (elf.auto_close_stream) elf.in_file.close();
|
||||
if (elf.auto_close_stream) elf.prealloc_file.close();
|
||||
}
|
||||
|
||||
pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader {
|
||||
var file_stream = elf.in_file.inStream();
|
||||
const in = &file_stream.stream;
|
||||
|
||||
section_loop: for (elf.section_headers) |*elf_section| {
|
||||
if (elf_section.sh_type == SHT_NULL) continue;
|
||||
|
||||
const name_offset = elf.string_section.offset + elf_section.name;
|
||||
try elf.in_file.seekTo(name_offset);
|
||||
try elf.seekable_stream.seekTo(name_offset);
|
||||
|
||||
for (name) |expected_c| {
|
||||
const target_c = try in.readByte();
|
||||
const target_c = try elf.in_stream.readByte();
|
||||
if (target_c == 0 or expected_c != target_c) continue :section_loop;
|
||||
}
|
||||
|
||||
{
|
||||
const null_byte = try in.readByte();
|
||||
const null_byte = try elf.in_stream.readByte();
|
||||
if (null_byte == 0) return elf_section;
|
||||
}
|
||||
}
|
||||
|
@ -549,7 +552,7 @@ pub const Elf = struct {
|
|||
}
|
||||
|
||||
pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void {
|
||||
try elf.in_file.seekTo(elf_section.offset);
|
||||
try elf.seekable_stream.seekTo(elf_section.offset);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ const std = @import("../index.zig");
|
|||
const math = std.math;
|
||||
const debug = std.debug;
|
||||
const assert = debug.assert;
|
||||
const assertError = debug.assertError;
|
||||
const mem = std.mem;
|
||||
const builtin = @import("builtin");
|
||||
const errol = @import("errol/index.zig");
|
||||
|
@ -811,13 +812,41 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
|
|||
|
||||
for (buf) |c| {
|
||||
const digit = try charToDigit(c, radix);
|
||||
x = try math.mul(T, x, radix);
|
||||
x = try math.add(T, x, digit);
|
||||
|
||||
if (x != 0) x = try math.mul(T, x, try math.cast(T, radix));
|
||||
x = try math.add(T, x, try math.cast(T, digit));
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
test "parseUnsigned" {
|
||||
assert((try parseUnsigned(u16, "050124", 10)) == 50124);
|
||||
assert((try parseUnsigned(u16, "65535", 10)) == 65535);
|
||||
assertError(parseUnsigned(u16, "65536", 10), error.Overflow);
|
||||
|
||||
assert((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff);
|
||||
assertError(parseUnsigned(u64, "10000000000000000", 16), error.Overflow);
|
||||
|
||||
assert((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF);
|
||||
|
||||
assert((try parseUnsigned(u7, "1", 10)) == 1);
|
||||
assert((try parseUnsigned(u7, "1000", 2)) == 8);
|
||||
|
||||
assertError(parseUnsigned(u32, "f", 10), error.InvalidCharacter);
|
||||
assertError(parseUnsigned(u8, "109", 8), error.InvalidCharacter);
|
||||
|
||||
assert((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747);
|
||||
|
||||
// these numbers should fit even though the radix itself doesn't fit in the destination type
|
||||
assert((try parseUnsigned(u1, "0", 10)) == 0);
|
||||
assert((try parseUnsigned(u1, "1", 10)) == 1);
|
||||
assertError(parseUnsigned(u1, "2", 10), error.Overflow);
|
||||
assert((try parseUnsigned(u1, "001", 16)) == 1);
|
||||
assert((try parseUnsigned(u2, "3", 16)) == 3);
|
||||
assertError(parseUnsigned(u2, "4", 16), error.Overflow);
|
||||
}
|
||||
|
||||
pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
|
||||
const value = switch (c) {
|
||||
'0'...'9' => c - '0',
|
||||
|
|
|
@ -126,6 +126,14 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3
|
|||
};
|
||||
}
|
||||
|
||||
pub fn getOrPutValue(self: *Self, key: K, value: V) !*KV {
|
||||
const res = try self.getOrPut(key);
|
||||
if (!res.found_existing)
|
||||
res.kv.value = value;
|
||||
|
||||
return res.kv;
|
||||
}
|
||||
|
||||
fn ensureCapacity(self: *Self) !void {
|
||||
if (self.entries.len == 0) {
|
||||
return self.initCapacity(16);
|
||||
|
@ -354,6 +362,12 @@ test "basic hash map usage" {
|
|||
gop2.kv.value = 42;
|
||||
assert(map.get(99).?.value == 42);
|
||||
|
||||
const gop3 = try map.getOrPutValue(5, 5);
|
||||
assert(gop3.value == 77);
|
||||
|
||||
const gop4 = try map.getOrPutValue(100, 41);
|
||||
assert(gop4.value == 41);
|
||||
|
||||
assert(map.contains(2));
|
||||
assert(map.get(2).?.value == 22);
|
||||
_ = map.remove(2);
|
||||
|
|
78
std/io.zig
78
std/io.zig
|
@ -32,6 +32,8 @@ pub fn getStdIn() GetStdIoErrs!File {
|
|||
return File.openHandle(handle);
|
||||
}
|
||||
|
||||
pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
|
||||
|
||||
pub fn InStream(comptime ReadError: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
|
@ -683,25 +685,73 @@ test "import io tests" {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn readLine(buf: []u8) !usize {
|
||||
var stdin = getStdIn() catch return error.StdInUnavailable;
|
||||
var adapter = stdin.inStream();
|
||||
var stream = &adapter.stream;
|
||||
var index: usize = 0;
|
||||
pub fn readLine(buf: *std.Buffer) ![]u8 {
|
||||
var stdin = try getStdIn();
|
||||
var stdin_stream = stdin.inStream();
|
||||
return readLineFrom(&stdin_stream.stream, buf);
|
||||
}
|
||||
|
||||
/// Reads all characters until the next newline into buf, and returns
|
||||
/// a slice of the characters read (excluding the newline character(s)).
|
||||
pub fn readLineFrom(stream: var, buf: *std.Buffer) ![]u8 {
|
||||
const start = buf.len();
|
||||
while (true) {
|
||||
const byte = stream.readByte() catch return error.EndOfFile;
|
||||
const byte = try stream.readByte();
|
||||
switch (byte) {
|
||||
'\r' => {
|
||||
// trash the following \n
|
||||
_ = stream.readByte() catch return error.EndOfFile;
|
||||
return index;
|
||||
},
|
||||
'\n' => return index,
|
||||
else => {
|
||||
if (index == buf.len) return error.InputTooLong;
|
||||
buf[index] = byte;
|
||||
index += 1;
|
||||
_ = try stream.readByte();
|
||||
return buf.toSlice()[start..];
|
||||
},
|
||||
'\n' => return buf.toSlice()[start..],
|
||||
else => try buf.appendByte(byte),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test "io.readLineFrom" {
|
||||
var bytes: [128]u8 = undefined;
|
||||
const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
|
||||
|
||||
var buf = try std.Buffer.initSize(allocator, 0);
|
||||
var mem_stream = SliceInStream.init(
|
||||
\\Line 1
|
||||
\\Line 22
|
||||
\\Line 333
|
||||
);
|
||||
const stream = &mem_stream.stream;
|
||||
|
||||
debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf)));
|
||||
debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf)));
|
||||
debug.assertError(readLineFrom(stream, &buf), error.EndOfStream);
|
||||
debug.assert(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333"));
|
||||
}
|
||||
|
||||
pub fn readLineSlice(slice: []u8) ![]u8 {
|
||||
var stdin = try getStdIn();
|
||||
var stdin_stream = stdin.inStream();
|
||||
return readLineSliceFrom(&stdin_stream.stream, slice);
|
||||
}
|
||||
|
||||
/// Reads all characters until the next newline into slice, and returns
|
||||
/// a slice of the characters read (excluding the newline character(s)).
|
||||
pub fn readLineSliceFrom(stream: var, slice: []u8) ![]u8 {
|
||||
// We cannot use Buffer.fromOwnedSlice, as it wants to append a null byte
|
||||
// after taking ownership, which would always require an allocation.
|
||||
var buf = std.Buffer{ .list = std.ArrayList(u8).fromOwnedSlice(debug.failing_allocator, slice) };
|
||||
try buf.resize(0);
|
||||
return try readLineFrom(stream, &buf);
|
||||
}
|
||||
|
||||
test "io.readLineSliceFrom" {
|
||||
var buf: [7]u8 = undefined;
|
||||
var mem_stream = SliceInStream.init(
|
||||
\\Line 1
|
||||
\\Line 22
|
||||
\\Line 333
|
||||
);
|
||||
const stream = &mem_stream.stream;
|
||||
|
||||
debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..])));
|
||||
debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory);
|
||||
}
|
||||
|
|
32
std/io/seekable_stream.zig
Normal file
32
std/io/seekable_stream.zig
Normal file
|
@ -0,0 +1,32 @@
|
|||
const std = @import("../index.zig");
|
||||
const InStream = std.io.InStream;
|
||||
|
||||
pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type {
|
||||
return struct {
|
||||
const Self = @This();
|
||||
pub const SeekError = SeekErrorType;
|
||||
pub const GetSeekPosError = GetSeekPosErrorType;
|
||||
|
||||
seekToFn: fn (self: *Self, pos: usize) SeekError!void,
|
||||
seekForwardFn: fn (self: *Self, pos: isize) SeekError!void,
|
||||
|
||||
getPosFn: fn (self: *Self) GetSeekPosError!usize,
|
||||
getEndPosFn: fn (self: *Self) GetSeekPosError!usize,
|
||||
|
||||
pub fn seekTo(self: *Self, pos: usize) SeekError!void {
|
||||
return self.seekToFn(self, pos);
|
||||
}
|
||||
|
||||
pub fn seekForward(self: *Self, amt: isize) SeekError!void {
|
||||
return self.seekForwardFn(self, amt);
|
||||
}
|
||||
|
||||
pub fn getEndPos(self: *Self) GetSeekPosError!usize {
|
||||
return self.getEndPosFn(self);
|
||||
}
|
||||
|
||||
pub fn getPos(self: *Self) GetSeekPosError!usize {
|
||||
return self.getPosFn(self);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -82,6 +82,28 @@ pub fn LinkedList(comptime T: type) type {
|
|||
list.len += 1;
|
||||
}
|
||||
|
||||
/// Concatenate list2 onto the end of list1, removing all entries from the former.
|
||||
///
|
||||
/// Arguments:
|
||||
/// list1: the list to concatenate onto
|
||||
/// list2: the list to be concatenated
|
||||
pub fn concatByMoving(list1: *Self, list2: *Self) void {
|
||||
const l2_first = list2.first orelse return;
|
||||
if (list1.last) |l1_last| {
|
||||
l1_last.next = list2.first;
|
||||
l2_first.prev = list1.last;
|
||||
list1.len += list2.len;
|
||||
} else {
|
||||
// list1 was empty
|
||||
list1.first = list2.first;
|
||||
list1.len = list2.len;
|
||||
}
|
||||
list1.last = list2.last;
|
||||
list2.first = null;
|
||||
list2.last = null;
|
||||
list2.len = 0;
|
||||
}
|
||||
|
||||
/// Insert a new node at the end of the list.
|
||||
///
|
||||
/// Arguments:
|
||||
|
@ -247,3 +269,77 @@ test "basic linked list test" {
|
|||
assert(list.last.?.data == 4);
|
||||
assert(list.len == 2);
|
||||
}
|
||||
|
||||
test "linked list concatenation" {
|
||||
const allocator = debug.global_allocator;
|
||||
var list1 = LinkedList(u32).init();
|
||||
var list2 = LinkedList(u32).init();
|
||||
|
||||
var one = try list1.createNode(1, allocator);
|
||||
defer list1.destroyNode(one, allocator);
|
||||
var two = try list1.createNode(2, allocator);
|
||||
defer list1.destroyNode(two, allocator);
|
||||
var three = try list1.createNode(3, allocator);
|
||||
defer list1.destroyNode(three, allocator);
|
||||
var four = try list1.createNode(4, allocator);
|
||||
defer list1.destroyNode(four, allocator);
|
||||
var five = try list1.createNode(5, allocator);
|
||||
defer list1.destroyNode(five, allocator);
|
||||
|
||||
list1.append(one);
|
||||
list1.append(two);
|
||||
list2.append(three);
|
||||
list2.append(four);
|
||||
list2.append(five);
|
||||
|
||||
list1.concatByMoving(&list2);
|
||||
|
||||
assert(list1.last == five);
|
||||
assert(list1.len == 5);
|
||||
assert(list2.first == null);
|
||||
assert(list2.last == null);
|
||||
assert(list2.len == 0);
|
||||
|
||||
// Traverse forwards.
|
||||
{
|
||||
var it = list1.first;
|
||||
var index: u32 = 1;
|
||||
while (it) |node| : (it = node.next) {
|
||||
assert(node.data == index);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse backwards.
|
||||
{
|
||||
var it = list1.last;
|
||||
var index: u32 = 1;
|
||||
while (it) |node| : (it = node.prev) {
|
||||
assert(node.data == (6 - index));
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Swap them back, this verifies that concating to an empty list works.
|
||||
list2.concatByMoving(&list1);
|
||||
|
||||
// Traverse forwards.
|
||||
{
|
||||
var it = list2.first;
|
||||
var index: u32 = 1;
|
||||
while (it) |node| : (it = node.next) {
|
||||
assert(node.data == index);
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse backwards.
|
||||
{
|
||||
var it = list2.last;
|
||||
var index: u32 = 1;
|
||||
while (it) |node| : (it = node.prev) {
|
||||
assert(node.data == (6 - index));
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -228,7 +228,14 @@ pub const File = struct {
|
|||
return os.isTty(self.handle);
|
||||
}
|
||||
|
||||
pub fn seekForward(self: File, amount: isize) !void {
|
||||
pub const SeekError = error{
|
||||
/// TODO make this error impossible to get
|
||||
Overflow,
|
||||
Unseekable,
|
||||
Unexpected,
|
||||
};
|
||||
|
||||
pub fn seekForward(self: File, amount: isize) SeekError!void {
|
||||
switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);
|
||||
|
@ -259,7 +266,7 @@ pub const File = struct {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn seekTo(self: File, pos: usize) !void {
|
||||
pub fn seekTo(self: File, pos: usize) SeekError!void {
|
||||
switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
const ipos = try math.cast(isize, pos);
|
||||
|
@ -293,7 +300,14 @@ pub const File = struct {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn getPos(self: File) !usize {
|
||||
pub const GetSeekPosError = error{
|
||||
Overflow,
|
||||
SystemResources,
|
||||
Unseekable,
|
||||
Unexpected,
|
||||
};
|
||||
|
||||
pub fn getPos(self: File) GetSeekPosError!usize {
|
||||
switch (builtin.os) {
|
||||
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
|
||||
const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
|
||||
|
@ -323,13 +337,13 @@ pub const File = struct {
|
|||
}
|
||||
|
||||
assert(pos >= 0);
|
||||
return math.cast(usize, pos) catch error.FilePosLargerThanPointerRange;
|
||||
return math.cast(usize, pos);
|
||||
},
|
||||
else => @compileError("unsupported OS"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getEndPos(self: File) !usize {
|
||||
pub fn getEndPos(self: File) GetSeekPosError!usize {
|
||||
if (is_posix) {
|
||||
const stat = try os.posixFStat(self.handle);
|
||||
return @intCast(usize, stat.size);
|
||||
|
@ -431,6 +445,18 @@ pub const File = struct {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn seekableStream(file: File) SeekableStream {
|
||||
return SeekableStream{
|
||||
.file = file,
|
||||
.stream = SeekableStream.Stream{
|
||||
.seekToFn = SeekableStream.seekToFn,
|
||||
.seekForwardFn = SeekableStream.seekForwardFn,
|
||||
.getPosFn = SeekableStream.getPosFn,
|
||||
.getEndPosFn = SeekableStream.getEndPosFn,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// Implementation of io.InStream trait for File
|
||||
pub const InStream = struct {
|
||||
file: File,
|
||||
|
@ -458,4 +484,32 @@ pub const File = struct {
|
|||
return self.file.write(bytes);
|
||||
}
|
||||
};
|
||||
|
||||
/// Implementation of io.SeekableStream trait for File
|
||||
pub const SeekableStream = struct {
|
||||
file: File,
|
||||
stream: Stream,
|
||||
|
||||
pub const Stream = io.SeekableStream(SeekError, GetSeekPosError);
|
||||
|
||||
pub fn seekToFn(seekable_stream: *Stream, pos: usize) SeekError!void {
|
||||
const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
|
||||
return self.file.seekTo(pos);
|
||||
}
|
||||
|
||||
pub fn seekForwardFn(seekable_stream: *Stream, amt: isize) SeekError!void {
|
||||
const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
|
||||
return self.file.seekForward(amt);
|
||||
}
|
||||
|
||||
pub fn getEndPosFn(seekable_stream: *Stream) GetSeekPosError!usize {
|
||||
const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
|
||||
return self.file.getEndPos();
|
||||
}
|
||||
|
||||
pub fn getPosFn(seekable_stream: *Stream) GetSeekPosError!usize {
|
||||
const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
|
||||
return self.file.getPos();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -208,7 +208,7 @@ pub const Utf8View = struct {
|
|||
}
|
||||
};
|
||||
|
||||
const Utf8Iterator = struct {
|
||||
pub const Utf8Iterator = struct {
|
||||
bytes: []const u8,
|
||||
i: usize,
|
||||
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
const tests = @import("tests.zig");
|
||||
|
||||
pub fn addCases(cases: *tests.CompileErrorContext) void {
|
||||
cases.add(
|
||||
"error note for function parameter incompatibility",
|
||||
\\fn do_the_thing(func: fn (arg: i32) void) void {}
|
||||
\\fn bar(arg: bool) void {}
|
||||
\\export fn entry() void {
|
||||
\\ do_the_thing(bar);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:4:18: error: expected type 'fn(i32) void', found 'fn(bool) void",
|
||||
".tmp_source.zig:4:18: note: parameter 0: 'bool' cannot cast into 'i32'",
|
||||
);
|
||||
|
||||
cases.add(
|
||||
"cast negative value to unsigned integer",
|
||||
\\comptime {
|
||||
|
|
Loading…
Reference in New Issue
Block a user