AK: Make LEB128 decoding work with read_value

This commit is contained in:
Tim Schumacher 2023-01-30 00:02:38 +01:00 committed by Andrew Kaster
parent 787f4d639a
commit 47531a42a9
Notes: sideshowbarker 2024-07-17 04:32:07 +09:00
9 changed files with 135 additions and 148 deletions

View File

@ -12,11 +12,22 @@
namespace AK { namespace AK {
struct LEB128 { template<typename ValueType>
template<typename ValueType = size_t> class [[gnu::packed]] LEB128 {
static ErrorOr<void> read_unsigned(AK::Stream& stream, ValueType& result) public:
constexpr LEB128() = default;
constexpr LEB128(ValueType value)
: m_value(value)
{ {
result = 0; }
constexpr operator ValueType() const { return m_value; }
static ErrorOr<LEB128<ValueType>> read_from_stream(AK::Stream& stream)
requires(Unsigned<ValueType>)
{
ValueType result {};
size_t num_bytes = 0; size_t num_bytes = 0;
while (true) { while (true) {
if (stream.is_eof()) if (stream.is_eof())
@ -39,11 +50,11 @@ struct LEB128 {
++num_bytes; ++num_bytes;
} }
return {}; return LEB128<ValueType> { result };
} }
template<typename ValueType = ssize_t> static ErrorOr<LEB128<ValueType>> read_from_stream(AK::Stream& stream)
static ErrorOr<void> read_signed(AK::Stream& stream, ValueType& result) requires(Signed<ValueType>)
{ {
// Note: We read into a u64 to simplify the parsing logic; // Note: We read into a u64 to simplify the parsing logic;
// result is range checked into ValueType after parsing. // result is range checked into ValueType after parsing.
@ -52,7 +63,7 @@ struct LEB128 {
i64 temp = 0; i64 temp = 0;
size_t num_bytes = 0; size_t num_bytes = 0;
u8 byte = 0; u8 byte = 0;
result = 0; ValueType result {};
do { do {
if (stream.is_eof()) if (stream.is_eof())
@ -87,8 +98,11 @@ struct LEB128 {
result = static_cast<ValueType>(temp); result = static_cast<ValueType>(temp);
return {}; return LEB128<ValueType> { result };
} }
private:
ValueType m_value { 0 };
}; };
} }

View File

@ -21,11 +21,11 @@ TEST_CASE(single_byte)
buf[0] = i; buf[0] = i;
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_unsigned(*stream, output).is_error()); output = MUST(stream->read_value<LEB128<u32>>());
EXPECT_EQ(output, i); EXPECT_EQ(output, i);
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_signed(*stream, output_signed).is_error()); output_signed = MUST(stream->read_value<LEB128<i32>>());
EXPECT_EQ(output_signed, i); EXPECT_EQ(output_signed, i);
} }
@ -34,11 +34,11 @@ TEST_CASE(single_byte)
buf[0] = i; buf[0] = i;
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_unsigned(*stream, output).is_error()); output = MUST(stream->read_value<LEB128<u32>>());
EXPECT_EQ(output, i); EXPECT_EQ(output, i);
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_signed(*stream, output_signed).is_error()); output_signed = MUST(stream->read_value<LEB128<i32>>());
EXPECT_EQ(output_signed, (i | (-1 & (~0x3F)))); EXPECT_EQ(output_signed, (i | (-1 & (~0x3F))));
} }
// MSB set, but input too short // MSB set, but input too short
@ -46,10 +46,10 @@ TEST_CASE(single_byte)
buf[0] = static_cast<u8>(i); buf[0] = static_cast<u8>(i);
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(LEB128::read_unsigned(*stream, output).is_error()); EXPECT(stream->read_value<LEB128<u32>>().is_error());
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(LEB128::read_signed(*stream, output_signed).is_error()); EXPECT(stream->read_value<LEB128<i32>>().is_error());
} }
} }
@ -69,11 +69,11 @@ TEST_CASE(two_bytes)
buf[1] = j; buf[1] = j;
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_unsigned(*stream, output).is_error()); output = MUST(stream->read_value<LEB128<u32>>());
EXPECT_EQ(output, (static_cast<u32>(j) << 7) + (i & 0x7F)); EXPECT_EQ(output, (static_cast<u32>(j) << 7) + (i & 0x7F));
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_signed(*stream, output_signed).is_error()); output_signed = MUST(stream->read_value<LEB128<i32>>());
EXPECT_EQ(output_signed, (static_cast<i32>(j) << 7) + (i & 0x7F)); EXPECT_EQ(output_signed, (static_cast<i32>(j) << 7) + (i & 0x7F));
} }
@ -82,11 +82,11 @@ TEST_CASE(two_bytes)
buf[1] = j; buf[1] = j;
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_unsigned(*stream, output).is_error()); output = MUST(stream->read_value<LEB128<u32>>());
EXPECT_EQ(output, (static_cast<u32>(j) << 7) + (i & 0x7F)); EXPECT_EQ(output, (static_cast<u32>(j) << 7) + (i & 0x7F));
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_signed(*stream, output_signed).is_error()); output_signed = MUST(stream->read_value<LEB128<i32>>());
EXPECT_EQ(output_signed, ((static_cast<i32>(j) << 7) + (i & 0x7F)) | (-1 & (~0x3FFF))); EXPECT_EQ(output_signed, ((static_cast<i32>(j) << 7) + (i & 0x7F)) | (-1 & (~0x3FFF)));
} }
@ -95,10 +95,10 @@ TEST_CASE(two_bytes)
buf[1] = static_cast<u8>(j); buf[1] = static_cast<u8>(j);
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(LEB128::read_unsigned(*stream, output).is_error()); EXPECT(stream->read_value<LEB128<u32>>().is_error());
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(LEB128::read_signed(*stream, output_signed).is_error()); EXPECT(stream->read_value<LEB128<i32>>().is_error());
} }
} }
} }
@ -107,27 +107,22 @@ TEST_CASE(overflow_sizeof_output_unsigned)
{ {
u8 u32_max_plus_one[] = { 0x80, 0x80, 0x80, 0x80, 0x10 }; u8 u32_max_plus_one[] = { 0x80, 0x80, 0x80, 0x80, 0x10 };
{ {
u32 out = 0;
auto stream = MUST(FixedMemoryStream::construct(ReadonlyBytes { u32_max_plus_one, sizeof(u32_max_plus_one) })); auto stream = MUST(FixedMemoryStream::construct(ReadonlyBytes { u32_max_plus_one, sizeof(u32_max_plus_one) }));
EXPECT(LEB128::read_unsigned(*stream, out).is_error()); EXPECT(stream->read_value<LEB128<u32>>().is_error());
EXPECT_EQ(out, 0u);
u64 out64 = 0;
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_unsigned(*stream, out64).is_error()); u64 out64 = MUST(stream->read_value<LEB128<u64>>());
EXPECT_EQ(out64, static_cast<u64>(NumericLimits<u32>::max()) + 1); EXPECT_EQ(out64, static_cast<u64>(NumericLimits<u32>::max()) + 1);
} }
u8 u32_max[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x0F }; u8 u32_max[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x0F };
{ {
u32 out = 0;
auto stream = MUST(FixedMemoryStream::construct(ReadonlyBytes { u32_max, sizeof(u32_max) })); auto stream = MUST(FixedMemoryStream::construct(ReadonlyBytes { u32_max, sizeof(u32_max) }));
EXPECT(!LEB128::read_unsigned(*stream, out).is_error()); u32 out = MUST(stream->read_value<LEB128<u32>>());
EXPECT_EQ(out, NumericLimits<u32>::max()); EXPECT_EQ(out, NumericLimits<u32>::max());
u64 out64 = 0;
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_unsigned(*stream, out64).is_error()); u64 out64 = MUST(stream->read_value<LEB128<u64>>());
EXPECT_EQ(out64, NumericLimits<u32>::max()); EXPECT_EQ(out64, NumericLimits<u32>::max());
} }
} }
@ -136,53 +131,43 @@ TEST_CASE(overflow_sizeof_output_signed)
{ {
u8 i32_max_plus_one[] = { 0x80, 0x80, 0x80, 0x80, 0x08 }; u8 i32_max_plus_one[] = { 0x80, 0x80, 0x80, 0x80, 0x08 };
{ {
i32 out = 0;
auto stream = MUST(FixedMemoryStream::construct(ReadonlyBytes { i32_max_plus_one, sizeof(i32_max_plus_one) })); auto stream = MUST(FixedMemoryStream::construct(ReadonlyBytes { i32_max_plus_one, sizeof(i32_max_plus_one) }));
EXPECT(LEB128::read_signed(*stream, out).is_error()); EXPECT(stream->read_value<LEB128<i32>>().is_error());
EXPECT_EQ(out, 0);
i64 out64 = 0;
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_signed(*stream, out64).is_error()); i64 out64 = MUST(stream->read_value<LEB128<i64>>());
EXPECT_EQ(out64, static_cast<i64>(NumericLimits<i32>::max()) + 1); EXPECT_EQ(out64, static_cast<i64>(NumericLimits<i32>::max()) + 1);
} }
u8 i32_max[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x07 }; u8 i32_max[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x07 };
{ {
i32 out = 0;
auto stream = MUST(FixedMemoryStream::construct(ReadonlyBytes { i32_max, sizeof(i32_max) })); auto stream = MUST(FixedMemoryStream::construct(ReadonlyBytes { i32_max, sizeof(i32_max) }));
EXPECT(!LEB128::read_signed(*stream, out).is_error()); i32 out = MUST(stream->read_value<LEB128<i32>>());
EXPECT_EQ(out, NumericLimits<i32>::max()); EXPECT_EQ(out, NumericLimits<i32>::max());
i64 out64 = 0;
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_signed(*stream, out64).is_error()); i64 out64 = MUST(stream->read_value<LEB128<i64>>());
EXPECT_EQ(out64, NumericLimits<i32>::max()); EXPECT_EQ(out64, NumericLimits<i32>::max());
} }
u8 i32_min_minus_one[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x77 }; u8 i32_min_minus_one[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0x77 };
{ {
i32 out = 0;
auto stream = MUST(FixedMemoryStream::construct(ReadonlyBytes { i32_min_minus_one, sizeof(i32_min_minus_one) })); auto stream = MUST(FixedMemoryStream::construct(ReadonlyBytes { i32_min_minus_one, sizeof(i32_min_minus_one) }));
EXPECT(LEB128::read_signed(*stream, out).is_error()); EXPECT(stream->read_value<LEB128<i32>>().is_error());
EXPECT_EQ(out, 0);
i64 out64 = 0;
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_signed(*stream, out64).is_error()); i64 out64 = MUST(stream->read_value<LEB128<i64>>());
EXPECT_EQ(out64, static_cast<i64>(NumericLimits<i32>::min()) - 1); EXPECT_EQ(out64, static_cast<i64>(NumericLimits<i32>::min()) - 1);
} }
u8 i32_min[] = { 0x80, 0x80, 0x80, 0x80, 0x78 }; u8 i32_min[] = { 0x80, 0x80, 0x80, 0x80, 0x78 };
{ {
i32 out = 0;
auto stream = MUST(FixedMemoryStream::construct(ReadonlyBytes { i32_min, sizeof(i32_min) })); auto stream = MUST(FixedMemoryStream::construct(ReadonlyBytes { i32_min, sizeof(i32_min) }));
EXPECT(!LEB128::read_signed(*stream, out).is_error()); i32 out = MUST(stream->read_value<LEB128<i32>>());
EXPECT_EQ(out, NumericLimits<i32>::min()); EXPECT_EQ(out, NumericLimits<i32>::min());
i64 out64 = 0;
MUST(stream->seek(0)); MUST(stream->seek(0));
EXPECT(!LEB128::read_signed(*stream, out64).is_error()); i64 out64 = MUST(stream->read_value<LEB128<i64>>());
EXPECT_EQ(out64, NumericLimits<i32>::min()); EXPECT_EQ(out64, NumericLimits<i32>::min());
} }
} }

View File

@ -25,15 +25,13 @@ ErrorOr<void> AbbreviationsMap::populate_map()
TRY(abbreviation_stream->discard(m_offset)); TRY(abbreviation_stream->discard(m_offset));
while (!abbreviation_stream->is_eof()) { while (!abbreviation_stream->is_eof()) {
size_t abbreviation_code = 0; size_t abbreviation_code = TRY(abbreviation_stream->read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(*abbreviation_stream, abbreviation_code));
// An abbreviation code of 0 marks the end of the // An abbreviation code of 0 marks the end of the
// abbreviations for a given compilation unit // abbreviations for a given compilation unit
if (abbreviation_code == 0) if (abbreviation_code == 0)
break; break;
size_t tag {}; size_t tag = TRY(abbreviation_stream->read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(*abbreviation_stream, tag));
auto has_children = TRY(abbreviation_stream->read_value<u8>()); auto has_children = TRY(abbreviation_stream->read_value<u8>());
@ -43,17 +41,14 @@ ErrorOr<void> AbbreviationsMap::populate_map()
AttributeSpecification current_attribute_specification {}; AttributeSpecification current_attribute_specification {};
do { do {
size_t attribute_value = 0; size_t attribute_value = TRY(abbreviation_stream->read_value<LEB128<size_t>>());
size_t form_value = 0; size_t form_value = TRY(abbreviation_stream->read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(*abbreviation_stream, attribute_value));
TRY(LEB128::read_unsigned(*abbreviation_stream, form_value));
current_attribute_specification.attribute = static_cast<Attribute>(attribute_value); current_attribute_specification.attribute = static_cast<Attribute>(attribute_value);
current_attribute_specification.form = static_cast<AttributeDataForm>(form_value); current_attribute_specification.form = static_cast<AttributeDataForm>(form_value);
if (current_attribute_specification.form == AttributeDataForm::ImplicitConst) { if (current_attribute_specification.form == AttributeDataForm::ImplicitConst) {
ssize_t data_value; ssize_t data_value = TRY(abbreviation_stream->read_value<LEB128<ssize_t>>());
TRY(LEB128::read_signed(*abbreviation_stream, data_value));
current_attribute_specification.value = data_value; current_attribute_specification.value = data_value;
} }

View File

@ -30,8 +30,7 @@ ErrorOr<void> AddressRangesV5::for_each_range(Function<void(Range)> callback)
break; break;
} }
case RangeListEntryType::BaseAddressX: { case RangeListEntryType::BaseAddressX: {
FlatPtr index; FlatPtr index = TRY(m_range_lists_stream->read_value<LEB128<FlatPtr>>());
TRY(LEB128::read_unsigned(*m_range_lists_stream, index));
current_base_address = TRY(m_compilation_unit.get_address(index)); current_base_address = TRY(m_compilation_unit.get_address(index));
break; break;
} }
@ -44,30 +43,26 @@ ErrorOr<void> AddressRangesV5::for_each_range(Function<void(Range)> callback)
if (!base_address.has_value()) if (!base_address.has_value())
return Error::from_string_literal("Expected base_address for rangelist"); return Error::from_string_literal("Expected base_address for rangelist");
size_t start_offset, end_offset; size_t start_offset = TRY(m_range_lists_stream->read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(*m_range_lists_stream, start_offset)); size_t end_offset = TRY(m_range_lists_stream->read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(*m_range_lists_stream, end_offset));
callback(Range { start_offset + *base_address, end_offset + *base_address }); callback(Range { start_offset + *base_address, end_offset + *base_address });
break; break;
} }
case RangeListEntryType::StartLength: { case RangeListEntryType::StartLength: {
auto start = TRY(m_range_lists_stream->read_value<FlatPtr>()); auto start = TRY(m_range_lists_stream->read_value<FlatPtr>());
size_t length; size_t length = TRY(m_range_lists_stream->read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(*m_range_lists_stream, length));
callback(Range { start, start + length }); callback(Range { start, start + length });
break; break;
} }
case RangeListEntryType::StartXEndX: { case RangeListEntryType::StartXEndX: {
size_t start, end; size_t start = TRY(m_range_lists_stream->read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(*m_range_lists_stream, start)); size_t end = TRY(m_range_lists_stream->read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(*m_range_lists_stream, end));
callback(Range { TRY(m_compilation_unit.get_address(start)), TRY(m_compilation_unit.get_address(end)) }); callback(Range { TRY(m_compilation_unit.get_address(start)), TRY(m_compilation_unit.get_address(end)) });
break; break;
} }
case RangeListEntryType::StartXLength: { case RangeListEntryType::StartXLength: {
size_t start, length; size_t start = TRY(m_range_lists_stream->read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(*m_range_lists_stream, start)); size_t length = TRY(m_range_lists_stream->read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(*m_range_lists_stream, length));
auto start_addr = TRY(m_compilation_unit.get_address(start)); auto start_addr = TRY(m_compilation_unit.get_address(start));
callback(Range { start_addr, start_addr + length }); callback(Range { start_addr, start_addr + length });
break; break;

View File

@ -26,7 +26,7 @@ ErrorOr<void> DIE::rehydrate_from(u32 offset, Optional<u32> parent_offset)
auto stream = TRY(FixedMemoryStream::construct(m_compilation_unit.dwarf_info().debug_info_data())); auto stream = TRY(FixedMemoryStream::construct(m_compilation_unit.dwarf_info().debug_info_data()));
// Note: We can't just slice away from the input data here, since get_attribute_value will try to recover the original offset using seek(). // Note: We can't just slice away from the input data here, since get_attribute_value will try to recover the original offset using seek().
TRY(stream->seek(m_offset)); TRY(stream->seek(m_offset));
TRY(LEB128::read_unsigned(*stream, m_abbreviation_code)); m_abbreviation_code = TRY(stream->read_value<LEB128<size_t>>());
m_data_offset = TRY(stream->tell()); m_data_offset = TRY(stream->tell());
if (m_abbreviation_code == 0) { if (m_abbreviation_code == 0) {

View File

@ -120,15 +120,13 @@ ErrorOr<AttributeValue> DwarfInfo::get_attribute_value(AttributeDataForm form, s
break; break;
} }
case AttributeDataForm::SData: { case AttributeDataForm::SData: {
i64 data; i64 data = TRY(debug_info_stream.read_value<LEB128<i64>>());
TRY(LEB128::read_signed(debug_info_stream, data));
value.m_type = AttributeValue::Type::SignedNumber; value.m_type = AttributeValue::Type::SignedNumber;
value.m_data.as_signed = data; value.m_data.as_signed = data;
break; break;
} }
case AttributeDataForm::UData: { case AttributeDataForm::UData: {
u64 data; u64 data = TRY(debug_info_stream.read_value<LEB128<u64>>());
TRY(LEB128::read_unsigned(debug_info_stream, data));
value.m_type = AttributeValue::Type::UnsignedNumber; value.m_type = AttributeValue::Type::UnsignedNumber;
value.m_data.as_unsigned = data; value.m_data.as_unsigned = data;
break; break;
@ -169,8 +167,7 @@ ErrorOr<AttributeValue> DwarfInfo::get_attribute_value(AttributeDataForm form, s
break; break;
} }
case AttributeDataForm::ExprLoc: { case AttributeDataForm::ExprLoc: {
size_t length; size_t length = TRY(debug_info_stream.read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(debug_info_stream, length));
value.m_type = AttributeValue::Type::DwarfExpression; value.m_type = AttributeValue::Type::DwarfExpression;
TRY(assign_raw_bytes_value(length)); TRY(assign_raw_bytes_value(length));
break; break;
@ -202,8 +199,7 @@ ErrorOr<AttributeValue> DwarfInfo::get_attribute_value(AttributeDataForm form, s
} }
case AttributeDataForm::Block: { case AttributeDataForm::Block: {
value.m_type = AttributeValue::Type::RawBytes; value.m_type = AttributeValue::Type::RawBytes;
size_t length; size_t length = TRY(debug_info_stream.read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(debug_info_stream, length));
TRY(assign_raw_bytes_value(length)); TRY(assign_raw_bytes_value(length));
break; break;
} }
@ -240,8 +236,7 @@ ErrorOr<AttributeValue> DwarfInfo::get_attribute_value(AttributeDataForm form, s
break; break;
} }
case AttributeDataForm::StrX: { case AttributeDataForm::StrX: {
size_t index; size_t index = TRY(debug_info_stream.read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(debug_info_stream, index));
value.m_type = AttributeValue::Type::String; value.m_type = AttributeValue::Type::String;
value.m_data.as_unsigned = index; value.m_data.as_unsigned = index;
break; break;
@ -265,15 +260,13 @@ ErrorOr<AttributeValue> DwarfInfo::get_attribute_value(AttributeDataForm form, s
break; break;
} }
case AttributeDataForm::AddrX: { case AttributeDataForm::AddrX: {
size_t index; size_t index = TRY(debug_info_stream.read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(debug_info_stream, index));
value.m_type = AttributeValue::Type::Address; value.m_type = AttributeValue::Type::Address;
value.m_data.as_unsigned = index; value.m_data.as_unsigned = index;
break; break;
} }
case AttributeDataForm::RngListX: { case AttributeDataForm::RngListX: {
size_t index; size_t index = TRY(debug_info_stream.read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(debug_info_stream, index));
value.m_type = AttributeValue::Type::UnsignedNumber; value.m_type = AttributeValue::Type::UnsignedNumber;
value.m_data.as_unsigned = index; value.m_data.as_unsigned = index;
break; break;

View File

@ -44,17 +44,14 @@ ErrorOr<void> LineProgram::parse_path_entries(Function<void(PathEntry& entry)> c
Vector<PathEntryFormat> format_descriptions; Vector<PathEntryFormat> format_descriptions;
for (u8 i = 0; i < path_entry_format_count; i++) { for (u8 i = 0; i < path_entry_format_count; i++) {
UnderlyingType<ContentType> content_type; UnderlyingType<ContentType> content_type = TRY(m_stream.read_value<LEB128<UnderlyingType<ContentType>>>());
TRY(LEB128::read_unsigned(m_stream, content_type));
UnderlyingType<AttributeDataForm> data_form; UnderlyingType<AttributeDataForm> data_form = TRY(m_stream.read_value<LEB128<UnderlyingType<AttributeDataForm>>>());
TRY(LEB128::read_unsigned(m_stream, data_form));
format_descriptions.empend(static_cast<ContentType>(content_type), static_cast<AttributeDataForm>(data_form)); format_descriptions.empend(static_cast<ContentType>(content_type), static_cast<AttributeDataForm>(data_form));
} }
size_t paths_count = 0; size_t paths_count = TRY(m_stream.read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(m_stream, paths_count));
for (size_t i = 0; i < paths_count; i++) { for (size_t i = 0; i < paths_count; i++) {
PathEntry entry; PathEntry entry;
@ -85,11 +82,9 @@ ErrorOr<void> LineProgram::parse_path_entries(Function<void(PathEntry& entry)> c
PathEntry entry; PathEntry entry;
entry.path = path; entry.path = path;
if (list_type == PathListType::Filenames) { if (list_type == PathListType::Filenames) {
size_t directory_index = 0; size_t directory_index = TRY(m_stream.read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(m_stream, directory_index)); TRY(m_stream.read_value<LEB128<size_t>>()); // skip modification time
size_t _unused = 0; TRY(m_stream.read_value<LEB128<size_t>>()); // skip file size
TRY(LEB128::read_unsigned(m_stream, _unused)); // skip modification time
TRY(LEB128::read_unsigned(m_stream, _unused)); // skip file size
entry.directory_index = directory_index; entry.directory_index = directory_index;
dbgln_if(DWARF_DEBUG, "file: {}, directory index: {}", path, directory_index); dbgln_if(DWARF_DEBUG, "file: {}, directory index: {}", path, directory_index);
} }
@ -157,8 +152,7 @@ void LineProgram::reset_registers()
ErrorOr<void> LineProgram::handle_extended_opcode() ErrorOr<void> LineProgram::handle_extended_opcode()
{ {
size_t length = 0; size_t length = TRY(m_stream.read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(m_stream, length));
auto sub_opcode = TRY(m_stream.read_value<u8>()); auto sub_opcode = TRY(m_stream.read_value<u8>());
@ -176,8 +170,7 @@ ErrorOr<void> LineProgram::handle_extended_opcode()
} }
case ExtendedOpcodes::SetDiscriminator: { case ExtendedOpcodes::SetDiscriminator: {
dbgln_if(DWARF_DEBUG, "SetDiscriminator"); dbgln_if(DWARF_DEBUG, "SetDiscriminator");
size_t discriminator; [[maybe_unused]] size_t discriminator = TRY(m_stream.read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(m_stream, discriminator));
break; break;
} }
default: default:
@ -195,16 +188,14 @@ ErrorOr<void> LineProgram::handle_standard_opcode(u8 opcode)
break; break;
} }
case StandardOpcodes::AdvancePc: { case StandardOpcodes::AdvancePc: {
size_t operand = 0; size_t operand = TRY(m_stream.read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(m_stream, operand));
size_t delta = operand * m_unit_header.min_instruction_length(); size_t delta = operand * m_unit_header.min_instruction_length();
dbgln_if(DWARF_DEBUG, "AdvancePC by: {} to: {:p}", delta, m_address + delta); dbgln_if(DWARF_DEBUG, "AdvancePC by: {} to: {:p}", delta, m_address + delta);
m_address += delta; m_address += delta;
break; break;
} }
case StandardOpcodes::SetFile: { case StandardOpcodes::SetFile: {
size_t new_file_index = 0; size_t new_file_index = TRY(m_stream.read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(m_stream, new_file_index));
dbgln_if(DWARF_DEBUG, "SetFile: new file index: {}", new_file_index); dbgln_if(DWARF_DEBUG, "SetFile: new file index: {}", new_file_index);
m_file_index = new_file_index; m_file_index = new_file_index;
break; break;
@ -212,14 +203,12 @@ ErrorOr<void> LineProgram::handle_standard_opcode(u8 opcode)
case StandardOpcodes::SetColumn: { case StandardOpcodes::SetColumn: {
// not implemented // not implemented
dbgln_if(DWARF_DEBUG, "SetColumn"); dbgln_if(DWARF_DEBUG, "SetColumn");
size_t new_column; [[maybe_unused]] size_t new_column = TRY(m_stream.read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(m_stream, new_column));
break; break;
} }
case StandardOpcodes::AdvanceLine: { case StandardOpcodes::AdvanceLine: {
ssize_t line_delta; ssize_t line_delta = TRY(m_stream.read_value<LEB128<ssize_t>>());
TRY(LEB128::read_signed(m_stream, line_delta));
VERIFY(line_delta >= 0 || m_line >= (size_t)(-line_delta)); VERIFY(line_delta >= 0 || m_line >= (size_t)(-line_delta));
m_line += line_delta; m_line += line_delta;
dbgln_if(DWARF_DEBUG, "AdvanceLine: {}", m_line); dbgln_if(DWARF_DEBUG, "AdvanceLine: {}", m_line);
@ -239,8 +228,7 @@ ErrorOr<void> LineProgram::handle_standard_opcode(u8 opcode)
break; break;
} }
case StandardOpcodes::SetIsa: { case StandardOpcodes::SetIsa: {
size_t isa; size_t isa = TRY(m_stream.read_value<LEB128<size_t>>());
TRY(LEB128::read_unsigned(m_stream, isa));
dbgln_if(DWARF_DEBUG, "SetIsa: {}", isa); dbgln_if(DWARF_DEBUG, "SetIsa: {}", isa);
break; break;
} }

View File

@ -26,9 +26,10 @@ static auto parse_vector(AK::Stream& stream)
ScopeLogger<WASM_BINPARSER_DEBUG> logger; ScopeLogger<WASM_BINPARSER_DEBUG> logger;
if constexpr (requires { T::parse(stream); }) { if constexpr (requires { T::parse(stream); }) {
using ResultT = typename decltype(T::parse(stream))::ValueType; using ResultT = typename decltype(T::parse(stream))::ValueType;
size_t count; auto count_or_error = stream.read_value<LEB128<size_t>>();
if (LEB128::read_unsigned(stream, count).is_error()) if (count_or_error.is_error())
return ParseResult<Vector<ResultT>> { with_eof_check(stream, ParseError::ExpectedSize) }; return ParseResult<Vector<ResultT>> { with_eof_check(stream, ParseError::ExpectedSize) };
size_t count = count_or_error.release_value();
Vector<ResultT> entries; Vector<ResultT> entries;
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
@ -39,21 +40,24 @@ static auto parse_vector(AK::Stream& stream)
} }
return ParseResult<Vector<ResultT>> { move(entries) }; return ParseResult<Vector<ResultT>> { move(entries) };
} else { } else {
size_t count; auto count_or_error = stream.read_value<LEB128<size_t>>();
if (LEB128::read_unsigned(stream, count).is_error()) if (count_or_error.is_error())
return ParseResult<Vector<T>> { with_eof_check(stream, ParseError::ExpectedSize) }; return ParseResult<Vector<T>> { with_eof_check(stream, ParseError::ExpectedSize) };
size_t count = count_or_error.release_value();
Vector<T> entries; Vector<T> entries;
for (size_t i = 0; i < count; ++i) { for (size_t i = 0; i < count; ++i) {
if constexpr (IsSame<T, size_t>) { if constexpr (IsSame<T, size_t>) {
size_t value; auto value_or_error = stream.read_value<LEB128<size_t>>();
if (LEB128::read_unsigned(stream, value).is_error()) if (value_or_error.is_error())
return ParseResult<Vector<T>> { with_eof_check(stream, ParseError::ExpectedSize) }; return ParseResult<Vector<T>> { with_eof_check(stream, ParseError::ExpectedSize) };
size_t value = value_or_error.release_value();
entries.append(value); entries.append(value);
} else if constexpr (IsSame<T, ssize_t>) { } else if constexpr (IsSame<T, ssize_t>) {
ssize_t value; auto value_or_error = stream.read_value<LEB128<ssize_t>>();
if (LEB128::read_signed(stream, value).is_error()) if (value_or_error.is_error())
return ParseResult<Vector<T>> { with_eof_check(stream, ParseError::ExpectedSize) }; return ParseResult<Vector<T>> { with_eof_check(stream, ParseError::ExpectedSize) };
ssize_t value = value_or_error.release_value();
entries.append(value); entries.append(value);
} else if constexpr (IsSame<T, u8>) { } else if constexpr (IsSame<T, u8>) {
if (count > Constants::max_allowed_vector_size) if (count > Constants::max_allowed_vector_size)
@ -186,16 +190,17 @@ ParseResult<Limits> Limits::parse(AK::Stream& stream)
if (flag > 1) if (flag > 1)
return with_eof_check(stream, ParseError::InvalidTag); return with_eof_check(stream, ParseError::InvalidTag);
size_t min; auto min_or_error = stream.read_value<LEB128<size_t>>();
if (LEB128::read_unsigned(stream, min).is_error()) if (min_or_error.is_error())
return with_eof_check(stream, ParseError::ExpectedSize); return with_eof_check(stream, ParseError::ExpectedSize);
size_t min = min_or_error.release_value();
Optional<u32> max; Optional<u32> max;
if (flag) { if (flag) {
size_t value; auto value_or_error = stream.read_value<LEB128<size_t>>();
if (LEB128::read_unsigned(stream, value).is_error()) if (value_or_error.is_error())
return with_eof_check(stream, ParseError::ExpectedSize); return with_eof_check(stream, ParseError::ExpectedSize);
max = value; max = value_or_error.release_value();
} }
return Limits { static_cast<u32>(min), move(max) }; return Limits { static_cast<u32>(min), move(max) };
@ -263,9 +268,10 @@ ParseResult<BlockType> BlockType::parse(AK::Stream& stream)
ReconsumableStream new_stream { stream }; ReconsumableStream new_stream { stream };
new_stream.unread({ &kind, 1 }); new_stream.unread({ &kind, 1 });
ssize_t index_value; auto index_value_or_error = stream.read_value<LEB128<ssize_t>>();
if (LEB128::read_signed(new_stream, index_value).is_error()) if (index_value_or_error.is_error())
return with_eof_check(stream, ParseError::ExpectedIndex); return with_eof_check(stream, ParseError::ExpectedIndex);
ssize_t index_value = index_value_or_error.release_value();
if (index_value < 0) { if (index_value < 0) {
dbgln("Invalid type index {}", index_value); dbgln("Invalid type index {}", index_value);
@ -408,13 +414,15 @@ ParseResult<Vector<Instruction>> Instruction::parse(AK::Stream& stream, Instruct
case Instructions::i64_store16.value(): case Instructions::i64_store16.value():
case Instructions::i64_store32.value(): { case Instructions::i64_store32.value(): {
// op (align offset) // op (align offset)
size_t align; auto align_or_error = stream.read_value<LEB128<size_t>>();
if (LEB128::read_unsigned(stream, align).is_error()) if (align_or_error.is_error())
return with_eof_check(stream, ParseError::InvalidInput); return with_eof_check(stream, ParseError::InvalidInput);
size_t align = align_or_error.release_value();
size_t offset; auto offset_or_error = stream.read_value<LEB128<size_t>>();
if (LEB128::read_unsigned(stream, offset).is_error()) if (offset_or_error.is_error())
return with_eof_check(stream, ParseError::InvalidInput); return with_eof_check(stream, ParseError::InvalidInput);
size_t offset = offset_or_error.release_value();
resulting_instructions.append(Instruction { opcode, MemoryArgument { static_cast<u32>(align), static_cast<u32>(offset) } }); resulting_instructions.append(Instruction { opcode, MemoryArgument { static_cast<u32>(align), static_cast<u32>(offset) } });
break; break;
@ -456,18 +464,20 @@ ParseResult<Vector<Instruction>> Instruction::parse(AK::Stream& stream, Instruct
break; break;
} }
case Instructions::i32_const.value(): { case Instructions::i32_const.value(): {
i32 value; auto value_or_error = stream.read_value<LEB128<i32>>();
if (LEB128::read_signed(stream, value).is_error()) if (value_or_error.is_error())
return with_eof_check(stream, ParseError::ExpectedSignedImmediate); return with_eof_check(stream, ParseError::ExpectedSignedImmediate);
i32 value = value_or_error.release_value();
resulting_instructions.append(Instruction { opcode, value }); resulting_instructions.append(Instruction { opcode, value });
break; break;
} }
case Instructions::i64_const.value(): { case Instructions::i64_const.value(): {
// op literal // op literal
i64 value; auto value_or_error = stream.read_value<LEB128<i64>>();
if (LEB128::read_signed(stream, value).is_error()) if (value_or_error.is_error())
return with_eof_check(stream, ParseError::ExpectedSignedImmediate); return with_eof_check(stream, ParseError::ExpectedSignedImmediate);
i64 value = value_or_error.release_value();
resulting_instructions.append(Instruction { opcode, value }); resulting_instructions.append(Instruction { opcode, value });
break; break;
@ -665,9 +675,10 @@ ParseResult<Vector<Instruction>> Instruction::parse(AK::Stream& stream, Instruct
break; break;
case 0xfc: { case 0xfc: {
// These are multibyte instructions. // These are multibyte instructions.
u32 selector; auto selector_or_error = stream.read_value<LEB128<u32>>();
if (LEB128::read_unsigned(stream, selector).is_error()) if (selector_or_error.is_error())
return with_eof_check(stream, ParseError::InvalidInput); return with_eof_check(stream, ParseError::InvalidInput);
u32 selector = selector_or_error.release_value();
switch (selector) { switch (selector) {
case Instructions::i32_trunc_sat_f32_s_second: case Instructions::i32_trunc_sat_f32_s_second:
case Instructions::i32_trunc_sat_f32_u_second: case Instructions::i32_trunc_sat_f32_u_second:
@ -942,9 +953,10 @@ ParseResult<ExportSection::Export> ExportSection::Export::parse(AK::Stream& stre
auto tag = tag_or_error.release_value(); auto tag = tag_or_error.release_value();
size_t index; auto index_or_error = stream.read_value<LEB128<size_t>>();
if (LEB128::read_unsigned(stream, index).is_error()) if (index_or_error.is_error())
return with_eof_check(stream, ParseError::ExpectedIndex); return with_eof_check(stream, ParseError::ExpectedIndex);
size_t index = index_or_error.release_value();
switch (tag) { switch (tag) {
case Constants::extern_function_tag: case Constants::extern_function_tag:
@ -1138,9 +1150,10 @@ ParseResult<ElementSection> ElementSection::parse(AK::Stream& stream)
ParseResult<Locals> Locals::parse(AK::Stream& stream) ParseResult<Locals> Locals::parse(AK::Stream& stream)
{ {
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Locals"sv); ScopeLogger<WASM_BINPARSER_DEBUG> logger("Locals"sv);
size_t count; auto count_or_error = stream.read_value<LEB128<size_t>>();
if (LEB128::read_unsigned(stream, count).is_error()) if (count_or_error.is_error())
return with_eof_check(stream, ParseError::InvalidSize); return with_eof_check(stream, ParseError::InvalidSize);
size_t count = count_or_error.release_value();
if (count > Constants::max_allowed_function_locals_per_type) if (count > Constants::max_allowed_function_locals_per_type)
return with_eof_check(stream, ParseError::HugeAllocationRequested); return with_eof_check(stream, ParseError::HugeAllocationRequested);
@ -1167,9 +1180,10 @@ ParseResult<CodeSection::Func> CodeSection::Func::parse(AK::Stream& stream)
ParseResult<CodeSection::Code> CodeSection::Code::parse(AK::Stream& stream) ParseResult<CodeSection::Code> CodeSection::Code::parse(AK::Stream& stream)
{ {
ScopeLogger<WASM_BINPARSER_DEBUG> logger("Code"sv); ScopeLogger<WASM_BINPARSER_DEBUG> logger("Code"sv);
size_t size; auto size_or_error = stream.read_value<LEB128<size_t>>();
if (LEB128::read_unsigned(stream, size).is_error()) if (size_or_error.is_error())
return with_eof_check(stream, ParseError::InvalidSize); return with_eof_check(stream, ParseError::InvalidSize);
size_t size = size_or_error.release_value();
auto constrained_stream = ConstrainedStream { stream, size }; auto constrained_stream = ConstrainedStream { stream, size };
@ -1244,14 +1258,15 @@ ParseResult<DataSection> DataSection::parse(AK::Stream& stream)
ParseResult<DataCountSection> DataCountSection::parse([[maybe_unused]] AK::Stream& stream) ParseResult<DataCountSection> DataCountSection::parse([[maybe_unused]] AK::Stream& stream)
{ {
ScopeLogger<WASM_BINPARSER_DEBUG> logger("DataCountSection"sv); ScopeLogger<WASM_BINPARSER_DEBUG> logger("DataCountSection"sv);
u32 value; auto value_or_error = stream.read_value<LEB128<u32>>();
if (LEB128::read_unsigned(stream, value).is_error()) { if (value_or_error.is_error()) {
if (stream.is_eof()) { if (stream.is_eof()) {
// The section simply didn't contain anything. // The section simply didn't contain anything.
return DataCountSection { {} }; return DataCountSection { {} };
} }
return ParseError::ExpectedSize; return ParseError::ExpectedSize;
} }
u32 value = value_or_error.release_value();
return DataCountSection { value }; return DataCountSection { value };
} }
@ -1280,9 +1295,10 @@ ParseResult<Module> Module::parse(AK::Stream& stream)
auto section_id = section_id_or_error.release_value(); auto section_id = section_id_or_error.release_value();
size_t section_size; auto section_size_or_error = stream.read_value<LEB128<size_t>>();
if (LEB128::read_unsigned(stream, section_size).is_error()) if (section_size_or_error.is_error())
return with_eof_check(stream, ParseError::ExpectedSize); return with_eof_check(stream, ParseError::ExpectedSize);
size_t section_size = section_size_or_error.release_value();
auto section_stream = ConstrainedStream { stream, section_size }; auto section_stream = ConstrainedStream { stream, section_size };

View File

@ -65,9 +65,10 @@ template<typename T>
struct GenericIndexParser { struct GenericIndexParser {
static ParseResult<T> parse(AK::Stream& stream) static ParseResult<T> parse(AK::Stream& stream)
{ {
size_t value; auto value_or_error = stream.read_value<LEB128<size_t>>();
if (LEB128::read_unsigned(stream, value).is_error()) if (value_or_error.is_error())
return with_eof_check(stream, ParseError::ExpectedIndex); return with_eof_check(stream, ParseError::ExpectedIndex);
size_t value = value_or_error.release_value();
return T { value }; return T { value };
} }
}; };