Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/art/art/libdexfile/dex/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 14 kB image not shown  

Quelle  test_dex_file_builder.h

  Sprache: C
 

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#ifndef ART_LIBDEXFILE_DEX_TEST_DEX_FILE_BUILDER_H_
#define ART_LIBDEXFILE_DEX_TEST_DEX_FILE_BUILDER_H_

#include <zlib.h>

#include <cstring>
#include <map>
#include <set>
#include <vector>

#include <android-base/logging.h>

#include "base/array_ref.h"
#include "base/bit_utils.h"
#include "dex/dex_file_loader.h"
#include "dex/standard_dex_file.h"

namespace art {

class TestDexFileBuilder {
 public:
  TestDexFileBuilder()
      : strings_(), types_(), fields_(), protos_() {
  }

  void AddString(const std::string& str) {
    CHECK_LT(str.length(), 128u);  // Don't allow multi-byte length in uleb128.
    strings_.emplace(str, IdxAndDataOffset());
  }

  void AddType(const std::string& descriptor) {
    AddString(descriptor);
    types_.emplace(descriptor, 0u);
  }

  void AddField(const std::string& class_descriptor,
                const std::string& type,
                const std::string& name) {
    AddType(class_descriptor);
    AddType(type);
    AddString(name);
    FieldKey key = { class_descriptor, type, name };
    fields_.emplace(key, 0u);
  }

  void AddMethod(const std::string& class_descriptor,
                 const std::string& signature,
                 const std::string& name) {
    AddType(class_descriptor);
    AddString(name);

    ProtoKey proto_key = CreateProtoKey(signature);
    AddString(proto_key.shorty);
    AddType(proto_key.return_type);
    for (const auto& arg_type : proto_key.args) {
      AddType(arg_type);
    }
    auto it = protos_.emplace(proto_key, IdxAndDataOffset()).first;
    const ProtoKey* proto = &it->first;  // Valid as long as the element remains in protos_.

    MethodKey method_key = {
        class_descriptor, name, proto
    };
    methods_.emplace(method_key, 0u);
  }

  std::unique_ptr<const DexFile> Build(const std::string& dex_location,
                                       uint32_t location_checksum = 0u) {
    union {
      uint8_t data[sizeof(DexFile::Header)];
      uint64_t force_alignment;
    } header_data;
    std::memset(header_data.data, 0sizeof(header_data.data));
    DexFile::Header* header = reinterpret_cast<DexFile::Header*>(&header_data.data);
    std::copy_n(StandardDexFile::kDexMagic, 4u, header->magic_.data());
    std::copy_n(StandardDexFile::kDexMagicVersions[0], 4u, header->magic_.data() + 4u);
    header->header_size_ = sizeof(DexFile::Header);
    header->endian_tag_ = DexFile::kDexEndianConstant;
    header->link_size_ = 0u;  // Unused.
    header->link_off_ = 0u;  // Unused.
    header->map_off_ = 0u;  // Unused. TODO: This is wrong. Dex files created by this builder
                            //               cannot be verified. b/26808512

    uint32_t data_section_size = 0u;

    uint32_t string_ids_offset = sizeof(DexFile::Header);
    uint32_t string_idx = 0u;
    for (auto& entry : strings_) {
      entry.second.idx = string_idx;
      string_idx += 1u;
      entry.second.data_offset = data_section_size;
      data_section_size += entry.first.length() + 1/* length */ + 1u /* null-terminator */;
    }
    header->string_ids_size_ = strings_.size();
    header->string_ids_off_ = strings_.empty() ? 0u : string_ids_offset;

    uint32_t type_ids_offset = string_ids_offset + strings_.size() * sizeof(dex::StringId);
    uint32_t type_idx = 0u;
    for (auto& entry : types_) {
      entry.second = type_idx;
      type_idx += 1u;
    }
    header->type_ids_size_ = types_.size();
    header->type_ids_off_ = types_.empty() ? 0u : type_ids_offset;

    uint32_t proto_ids_offset = type_ids_offset + types_.size() * sizeof(dex::TypeId);
    uint32_t proto_idx = 0u;
    for (auto& entry : protos_) {
      entry.second.idx = proto_idx;
      proto_idx += 1u;
      size_t num_args = entry.first.args.size();
      if (num_args != 0u) {
        entry.second.data_offset = RoundUp(data_section_size, 4u);
        data_section_size = entry.second.data_offset + 4u + num_args * sizeof(dex::TypeItem);
      } else {
        entry.second.data_offset = 0u;
      }
    }
    header->proto_ids_size_ = protos_.size();
    header->proto_ids_off_ = protos_.empty() ? 0u : proto_ids_offset;

    uint32_t field_ids_offset = proto_ids_offset + protos_.size() * sizeof(dex::ProtoId);
    uint32_t field_idx = 0u;
    for (auto& entry : fields_) {
      entry.second = field_idx;
      field_idx += 1u;
    }
    header->field_ids_size_ = fields_.size();
    header->field_ids_off_ = fields_.empty() ? 0u : field_ids_offset;

    uint32_t method_ids_offset = field_ids_offset + fields_.size() * sizeof(dex::FieldId);
    uint32_t method_idx = 0u;
    for (auto& entry : methods_) {
      entry.second = method_idx;
      method_idx += 1u;
    }
    header->method_ids_size_ = methods_.size();
    header->method_ids_off_ = methods_.empty() ? 0u : method_ids_offset;

    // No class defs.
    header->class_defs_size_ = 0u;
    header->class_defs_off_ = 0u;

    uint32_t data_section_offset = method_ids_offset + methods_.size() * sizeof(dex::MethodId);
    header->data_size_ = data_section_size;
    header->data_off_ = (data_section_size != 0u) ? data_section_offset : 0u;

    uint32_t total_size = data_section_offset + data_section_size;
    std::vector<uint8_t> dex_file_data(total_size, 0u);

    for (const auto& entry : strings_) {
      CHECK_LT(entry.first.size(), 128u);
      uint32_t raw_offset = data_section_offset + entry.second.data_offset;
      dex_file_data[raw_offset] = static_cast<uint8_t>(entry.first.size());
      std::memcpy(&dex_file_data[raw_offset + 1], entry.first.c_str(), entry.first.size() + 1);
      Write32(dex_file_data,
              string_ids_offset + entry.second.idx * sizeof(dex::StringId),
              raw_offset);
    }

    for (const auto& entry : types_) {
      Write32(dex_file_data,
              type_ids_offset + entry.second * sizeof(dex::TypeId),
              GetStringIdx(entry.first));
      ++type_idx;
    }

    for (const auto& entry : protos_) {
      size_t num_args = entry.first.args.size();
      uint32_t type_list_offset =
          (num_args != 0u) ? data_section_offset + entry.second.data_offset : 0u;
      uint32_t raw_offset = proto_ids_offset + entry.second.idx * sizeof(dex::ProtoId);
      Write32(dex_file_data, raw_offset + 0u, GetStringIdx(entry.first.shorty));
      Write16(dex_file_data, raw_offset + 4u, GetTypeIdx(entry.first.return_type));
      Write32(dex_file_data, raw_offset + 8u, type_list_offset);
      if (num_args != 0u) {
        CHECK_NE(entry.second.data_offset, 0u);
        Write32(dex_file_data, type_list_offset, num_args);
        for (size_t i = 0; i != num_args; ++i) {
          Write16(dex_file_data,
                  type_list_offset + 4u + i * sizeof(dex::TypeItem),
                  GetTypeIdx(entry.first.args[i]));
        }
      }
    }

    for (const auto& entry : fields_) {
      uint32_t raw_offset = field_ids_offset + entry.second * sizeof(dex::FieldId);
      Write16(dex_file_data, raw_offset + 0u, GetTypeIdx(entry.first.class_descriptor));
      Write16(dex_file_data, raw_offset + 2u, GetTypeIdx(entry.first.type));
      Write32(dex_file_data, raw_offset + 4u, GetStringIdx(entry.first.name));
    }

    for (const auto& entry : methods_) {
      uint32_t raw_offset = method_ids_offset + entry.second * sizeof(dex::MethodId);
      Write16(dex_file_data, raw_offset + 0u, GetTypeIdx(entry.first.class_descriptor));
      auto it = protos_.find(*entry.first.proto);
      CHECK(it != protos_.end());
      Write16(dex_file_data, raw_offset + 2u, it->second.idx);
      Write32(dex_file_data, raw_offset + 4u, GetStringIdx(entry.first.name));
    }

    // Leave signature as zeros.

    header->file_size_ = dex_file_data.size();

    // Write the complete header early, as part of it needs to be checksummed.
    std::memcpy(&dex_file_data[0], header_data.data, sizeof(DexFile::Header));

    // Checksum starts after the checksum field.
    size_t skip = sizeof(header->magic_) + sizeof(header->checksum_);
    header->checksum_ = adler32(adler32(0L, Z_NULL, 0),
                                dex_file_data.data() + skip,
                                dex_file_data.size() - skip);

    // Write the complete header again, just simpler that way.
    std::memcpy(&dex_file_data[0], header_data.data, sizeof(DexFile::Header));

    // Do not protect the final data from writing. Some tests need to modify it.

    static constexpr bool kVerify = false;
    static constexpr bool kVerifyChecksum = false;
    std::string error_msg;
    DexFileLoader dex_file_loader(std::move(dex_file_data), dex_location);
    std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(location_checksum,
                                                                 /*oat_dex_file=*/nullptr,
                                                                 kVerify,
                                                                 kVerifyChecksum,
                                                                 &error_msg));
    CHECK(dex_file != nullptr) << error_msg;
    return dex_file;
  }

  uint32_t GetStringIdx(const std::string& type) {
    auto it = strings_.find(type);
    CHECK(it != strings_.end());
    return it->second.idx;
  }

  uint32_t GetTypeIdx(const std::string& type) {
    auto it = types_.find(type);
    CHECK(it != types_.end());
    return it->second;
  }

  uint32_t GetFieldIdx(const std::string& class_descriptor, const std::string& type,
                       const std::string& name) {
    FieldKey key = { class_descriptor, type, name };
    auto it = fields_.find(key);
    CHECK(it != fields_.end());
    return it->second;
  }

  uint32_t GetMethodIdx(const std::string& class_descriptor, const std::string& signature,
                        const std::string& name) {
    ProtoKey proto_key = CreateProtoKey(signature);
    MethodKey method_key = { class_descriptor, name, &proto_key };
    auto it = methods_.find(method_key);
    CHECK(it != methods_.end());
    return it->second;
  }

 private:
  struct IdxAndDataOffset {
    uint32_t idx;
    uint32_t data_offset;
  };

  struct FieldKey {
    const std::string class_descriptor;
    const std::string type;
    const std::string name;
  };
  struct FieldKeyComparator {
    bool operator()(const FieldKey& lhs, const FieldKey& rhs) const {
      if (lhs.class_descriptor != rhs.class_descriptor) {
        return lhs.class_descriptor < rhs.class_descriptor;
      }
      if (lhs.name != rhs.name) {
        return lhs.name < rhs.name;
      }
      return lhs.type < rhs.type;
    }
  };

  struct ProtoKey {
    std::string shorty;
    std::string return_type;
    std::vector<std::string> args;
  };
  struct ProtoKeyComparator {
    bool operator()(const ProtoKey& lhs, const ProtoKey& rhs) const {
      if (lhs.return_type != rhs.return_type) {
        return lhs.return_type < rhs.return_type;
      }
      size_t min_args = std::min(lhs.args.size(), rhs.args.size());
      for (size_t i = 0; i != min_args; ++i) {
        if (lhs.args[i] != rhs.args[i]) {
          return lhs.args[i] < rhs.args[i];
        }
      }
      return lhs.args.size() < rhs.args.size();
    }
  };

  struct MethodKey {
    std::string class_descriptor;
    std::string name;
    const ProtoKey* proto;
  };
  struct MethodKeyComparator {
    bool operator()(const MethodKey& lhs, const MethodKey& rhs) const {
      if (lhs.class_descriptor != rhs.class_descriptor) {
        return lhs.class_descriptor < rhs.class_descriptor;
      }
      if (lhs.name != rhs.name) {
        return lhs.name < rhs.name;
      }
      return ProtoKeyComparator()(*lhs.proto, *rhs.proto);
    }
  };

  ProtoKey CreateProtoKey(const std::string& signature) {
    CHECK_EQ(signature[0], '(');
    const char* args = signature.c_str() + 1;
    const char* args_end = std::strchr(args, ')');
    CHECK(args_end != nullptr);
    const char* return_type = args_end + 1;

    ProtoKey key = {
        std::string() + ((*return_type == '[') ? 'L' : *return_type),
        return_type,
        std::vector<std::string>()
    };
    while (args != args_end) {
      key.shorty += (*args == '[') ? 'L' : *args;
      const char* arg_start = args;
      while (*args == '[') {
        ++args;
      }
      if (*args == 'L') {
        do {
          ++args;
          CHECK_NE(args, args_end);
        } while (*args != ';');
      }
      ++args;
      key.args.emplace_back(arg_start, args);
    }
    return key;
  }

  static void Write32(std::vector<uint8_t>& dex_file_data, size_t offset, uint32_t value) {
    CHECK_LE(offset + 4u, dex_file_data.size());
    CHECK_EQ(dex_file_data[offset + 0], 0u);
    CHECK_EQ(dex_file_data[offset + 1], 0u);
    CHECK_EQ(dex_file_data[offset + 2], 0u);
    CHECK_EQ(dex_file_data[offset + 3], 0u);
    dex_file_data[offset + 0] = static_cast<uint8_t>(value >> 0);
    dex_file_data[offset + 1] = static_cast<uint8_t>(value >> 8);
    dex_file_data[offset + 2] = static_cast<uint8_t>(value >> 16);
    dex_file_data[offset + 3] = static_cast<uint8_t>(value >> 24);
  }

  static void Write16(std::vector<uint8_t>& dex_file_data, size_t offset, uint32_t value) {
    CHECK_LE(value, 0xffffu);
    CHECK_LE(offset + 2u, dex_file_data.size());
    CHECK_EQ(dex_file_data[offset + 0], 0u);
    CHECK_EQ(dex_file_data[offset + 1], 0u);
    dex_file_data[offset + 0] = static_cast<uint8_t>(value >> 0);
    dex_file_data[offset + 1] = static_cast<uint8_t>(value >> 8);
  }

  std::map<std::string, IdxAndDataOffset> strings_;
  std::map<std::string, uint32_t> types_;
  std::map<FieldKey, uint32_t, FieldKeyComparator> fields_;
  std::map<ProtoKey, IdxAndDataOffset, ProtoKeyComparator> protos_;
  std::map<MethodKey, uint32_t, MethodKeyComparator> methods_;
};

}  // namespace art

#endif  // ART_LIBDEXFILE_DEX_TEST_DEX_FILE_BUILDER_H_

Messung V0.5 in Prozent
C=90 H=96 G=93

¤ Dauer der Verarbeitung: 0.1 Sekunden  (vorverarbeitet am  2026-06-29) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.