1*523fa7a6SAndroid Build Coastguard Worker /*
2*523fa7a6SAndroid Build Coastguard Worker * Copyright (c) Meta Platforms, Inc. and affiliates.
3*523fa7a6SAndroid Build Coastguard Worker * All rights reserved.
4*523fa7a6SAndroid Build Coastguard Worker *
5*523fa7a6SAndroid Build Coastguard Worker * This source code is licensed under the BSD-style license found in the
6*523fa7a6SAndroid Build Coastguard Worker * LICENSE file in the root directory of this source tree.
7*523fa7a6SAndroid Build Coastguard Worker */
8*523fa7a6SAndroid Build Coastguard Worker
9*523fa7a6SAndroid Build Coastguard Worker #include <executorch/schema/extended_header.h>
10*523fa7a6SAndroid Build Coastguard Worker
11*523fa7a6SAndroid Build Coastguard Worker #include <cinttypes>
12*523fa7a6SAndroid Build Coastguard Worker #include <cstring>
13*523fa7a6SAndroid Build Coastguard Worker
14*523fa7a6SAndroid Build Coastguard Worker #include <executorch/runtime/core/error.h>
15*523fa7a6SAndroid Build Coastguard Worker #include <executorch/runtime/core/result.h>
16*523fa7a6SAndroid Build Coastguard Worker
17*523fa7a6SAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wdeprecated"
18*523fa7a6SAndroid Build Coastguard Worker
19*523fa7a6SAndroid Build Coastguard Worker namespace executorch {
20*523fa7a6SAndroid Build Coastguard Worker namespace runtime {
21*523fa7a6SAndroid Build Coastguard Worker
22*523fa7a6SAndroid Build Coastguard Worker namespace {
23*523fa7a6SAndroid Build Coastguard Worker
24*523fa7a6SAndroid Build Coastguard Worker /// The expected location of the header length field relative to the beginning
25*523fa7a6SAndroid Build Coastguard Worker /// of the header.
26*523fa7a6SAndroid Build Coastguard Worker static constexpr size_t kHeaderLengthOffset = ExtendedHeader::kMagicSize;
27*523fa7a6SAndroid Build Coastguard Worker
28*523fa7a6SAndroid Build Coastguard Worker /// The expected location of the program_size field relative to the beginning of
29*523fa7a6SAndroid Build Coastguard Worker /// the header.
30*523fa7a6SAndroid Build Coastguard Worker static constexpr size_t kHeaderProgramSizeOffset =
31*523fa7a6SAndroid Build Coastguard Worker kHeaderLengthOffset + sizeof(uint32_t);
32*523fa7a6SAndroid Build Coastguard Worker
33*523fa7a6SAndroid Build Coastguard Worker /// The expected location of the segment_base_offset field relative to the
34*523fa7a6SAndroid Build Coastguard Worker /// beginning of the header.
35*523fa7a6SAndroid Build Coastguard Worker static constexpr size_t kHeaderSegmentBaseOffsetOffset =
36*523fa7a6SAndroid Build Coastguard Worker kHeaderProgramSizeOffset + sizeof(uint64_t);
37*523fa7a6SAndroid Build Coastguard Worker
38*523fa7a6SAndroid Build Coastguard Worker /**
39*523fa7a6SAndroid Build Coastguard Worker * The size of the header that covers the fields known of by this version of
40*523fa7a6SAndroid Build Coastguard Worker * the code. It's ok for a header to be larger as long as the fields stay in
41*523fa7a6SAndroid Build Coastguard Worker * the same place, but this code will ignore any new fields.
42*523fa7a6SAndroid Build Coastguard Worker */
43*523fa7a6SAndroid Build Coastguard Worker static constexpr size_t kMinimumHeaderLength =
44*523fa7a6SAndroid Build Coastguard Worker kHeaderSegmentBaseOffsetOffset + sizeof(uint64_t);
45*523fa7a6SAndroid Build Coastguard Worker
46*523fa7a6SAndroid Build Coastguard Worker /// Interprets the 4 bytes at `data` as a little-endian uint32_t.
GetUInt32LE(const uint8_t * data)47*523fa7a6SAndroid Build Coastguard Worker uint32_t GetUInt32LE(const uint8_t* data) {
48*523fa7a6SAndroid Build Coastguard Worker return (uint32_t)data[0] | ((uint32_t)data[1] << 8) |
49*523fa7a6SAndroid Build Coastguard Worker ((uint32_t)data[2] << 16) | ((uint32_t)data[3] << 24);
50*523fa7a6SAndroid Build Coastguard Worker }
51*523fa7a6SAndroid Build Coastguard Worker
52*523fa7a6SAndroid Build Coastguard Worker /// Interprets the 8 bytes at `data` as a little-endian uint64_t.
GetUInt64LE(const uint8_t * data)53*523fa7a6SAndroid Build Coastguard Worker uint64_t GetUInt64LE(const uint8_t* data) {
54*523fa7a6SAndroid Build Coastguard Worker return (uint64_t)data[0] | ((uint64_t)data[1] << 8) |
55*523fa7a6SAndroid Build Coastguard Worker ((uint64_t)data[2] << 16) | ((uint64_t)data[3] << 24) |
56*523fa7a6SAndroid Build Coastguard Worker ((uint64_t)data[4] << 32) | ((uint64_t)data[5] << 40) |
57*523fa7a6SAndroid Build Coastguard Worker ((uint64_t)data[6] << 48) | ((uint64_t)data[7] << 56);
58*523fa7a6SAndroid Build Coastguard Worker }
59*523fa7a6SAndroid Build Coastguard Worker
60*523fa7a6SAndroid Build Coastguard Worker } // namespace
61*523fa7a6SAndroid Build Coastguard Worker
Parse(const void * data,size_t size)62*523fa7a6SAndroid Build Coastguard Worker /* static */ Result<ExtendedHeader> ExtendedHeader::Parse(
63*523fa7a6SAndroid Build Coastguard Worker const void* data,
64*523fa7a6SAndroid Build Coastguard Worker size_t size) {
65*523fa7a6SAndroid Build Coastguard Worker if (size < ExtendedHeader::kNumHeadBytes) {
66*523fa7a6SAndroid Build Coastguard Worker return Error::InvalidArgument;
67*523fa7a6SAndroid Build Coastguard Worker }
68*523fa7a6SAndroid Build Coastguard Worker const uint8_t* header =
69*523fa7a6SAndroid Build Coastguard Worker reinterpret_cast<const uint8_t*>(data) + kHeaderOffset;
70*523fa7a6SAndroid Build Coastguard Worker
71*523fa7a6SAndroid Build Coastguard Worker // Check magic bytes.
72*523fa7a6SAndroid Build Coastguard Worker if (std::memcmp(header, ExtendedHeader::kMagic, ExtendedHeader::kMagicSize) !=
73*523fa7a6SAndroid Build Coastguard Worker 0) {
74*523fa7a6SAndroid Build Coastguard Worker return Error::NotFound;
75*523fa7a6SAndroid Build Coastguard Worker }
76*523fa7a6SAndroid Build Coastguard Worker
77*523fa7a6SAndroid Build Coastguard Worker // Check header length.
78*523fa7a6SAndroid Build Coastguard Worker uint32_t header_length = GetUInt32LE(header + kHeaderLengthOffset);
79*523fa7a6SAndroid Build Coastguard Worker if (header_length < kMinimumHeaderLength) {
80*523fa7a6SAndroid Build Coastguard Worker ET_LOG(
81*523fa7a6SAndroid Build Coastguard Worker Error,
82*523fa7a6SAndroid Build Coastguard Worker "Extended header length %" PRIu32 " < %zu",
83*523fa7a6SAndroid Build Coastguard Worker header_length,
84*523fa7a6SAndroid Build Coastguard Worker kMinimumHeaderLength);
85*523fa7a6SAndroid Build Coastguard Worker return Error::InvalidProgram;
86*523fa7a6SAndroid Build Coastguard Worker }
87*523fa7a6SAndroid Build Coastguard Worker
88*523fa7a6SAndroid Build Coastguard Worker // The header is present and apparently valid.
89*523fa7a6SAndroid Build Coastguard Worker return ExtendedHeader{
90*523fa7a6SAndroid Build Coastguard Worker /*program_size=*/GetUInt64LE(header + kHeaderProgramSizeOffset),
91*523fa7a6SAndroid Build Coastguard Worker /*segment_base_offset=*/
92*523fa7a6SAndroid Build Coastguard Worker GetUInt64LE(header + kHeaderSegmentBaseOffsetOffset),
93*523fa7a6SAndroid Build Coastguard Worker };
94*523fa7a6SAndroid Build Coastguard Worker }
95*523fa7a6SAndroid Build Coastguard Worker
96*523fa7a6SAndroid Build Coastguard Worker // Define storage for the static.
97*523fa7a6SAndroid Build Coastguard Worker constexpr char ExtendedHeader::kMagic[kMagicSize];
98*523fa7a6SAndroid Build Coastguard Worker
99*523fa7a6SAndroid Build Coastguard Worker } // namespace runtime
100*523fa7a6SAndroid Build Coastguard Worker } // namespace executorch
101