mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-02-06 06:55:07 +00:00
Add aot binary analysis tool aot-analyzer (#3379)
Add aot binary analysis tool aot-analyzer, samples: ```bash # parse example.aot, and print basic information about AoT file $ ./aot-analyzer -i example.aot # parse example.aot, and print the size of text section of the AoT file $ ./aot-analyzer -t example.aot # compare these two files, and show the difference in function size between them $ ./aot-analyzer -c example.aot example.wasm ``` Signed-off-by: ganjing <ganjing@xiaomi.com>
This commit is contained in:
parent
1c2a8fca4e
commit
07eae7c424
88
test-tools/aot-analyzer/CMakeLists.txt
Normal file
88
test-tools/aot-analyzer/CMakeLists.txt
Normal file
|
@ -0,0 +1,88 @@
|
|||
# Copyright (C) 2019 Intel Corporation. All rights reserved.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
cmake_minimum_required (VERSION 3.14)
|
||||
|
||||
project (aot-analyzer)
|
||||
|
||||
set (CMAKE_CXX_STANDARD 17)
|
||||
|
||||
################ runtime settings ################
|
||||
string (TOLOWER ${CMAKE_HOST_SYSTEM_NAME} WAMR_BUILD_PLATFORM)
|
||||
if (APPLE)
|
||||
add_definitions(-DBH_PLATFORM_DARWIN)
|
||||
endif ()
|
||||
|
||||
# Reset default linker flags
|
||||
set (CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
|
||||
set (CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
|
||||
|
||||
set (WAMR_STRINGREF_IMPL_SOURCE "STUB")
|
||||
|
||||
# Set WAMR_BUILD_TARGET, currently values supported:
|
||||
# "X86_64", "AMD_64", "X86_32", "AARCH64[sub]", "ARM[sub]", "THUMB[sub]",
|
||||
# "MIPS", "XTENSA", "RISCV64[sub]", "RISCV32[sub]"
|
||||
if (NOT DEFINED WAMR_BUILD_TARGET)
|
||||
if (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm64|aarch64)")
|
||||
set (WAMR_BUILD_TARGET "AARCH64")
|
||||
elseif (CMAKE_SYSTEM_PROCESSOR STREQUAL "riscv64")
|
||||
set (WAMR_BUILD_TARGET "RISCV64")
|
||||
elseif (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
# Build as X86_64 by default in 64-bit platform
|
||||
set (WAMR_BUILD_TARGET "X86_64")
|
||||
elseif (CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
# Build as X86_32 by default in 32-bit platform
|
||||
set (WAMR_BUILD_TARGET "X86_32")
|
||||
else ()
|
||||
message(SEND_ERROR "Unsupported build target platform!")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED WAMR_BUILD_INTERP)
|
||||
# Enable Interpreter by default
|
||||
set (WAMR_BUILD_INTERP 1)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED WAMR_BUILD_AOT)
|
||||
# Enable AOT by default.
|
||||
set (WAMR_BUILD_AOT 1)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED WAMR_BUILD_MEMORY_PROFILING)
|
||||
# Enable reference types by default
|
||||
set (WAMR_BUILD_MEMORY_PROFILING 1)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED WAMR_BIG_ENDIAN)
|
||||
set (WAMR_BIG_ENDIAN 0)
|
||||
endif ()
|
||||
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wshadow -Wno-unused-parameter")
|
||||
# set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wconversion -Wsign-conversion")
|
||||
|
||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat -Wformat-security -Wno-unused")
|
||||
|
||||
if (WAMR_BUILD_TARGET MATCHES "X86_.*" OR WAMR_BUILD_TARGET STREQUAL "AMD_64")
|
||||
if (NOT (CMAKE_C_COMPILER MATCHES ".*clang.*" OR CMAKE_C_COMPILER_ID MATCHES ".*Clang"))
|
||||
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mindirect-branch-register")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# build out vmlib
|
||||
set (WAMR_ROOT_DIR ${CMAKE_CURRENT_LIST_DIR}/../..)
|
||||
include (${WAMR_ROOT_DIR}/build-scripts/runtime_lib.cmake)
|
||||
|
||||
add_library(vmlib ${WAMR_RUNTIME_LIB_SOURCE})
|
||||
|
||||
################ application related ################
|
||||
include_directories(./include)
|
||||
include_directories(${CMAKE_CURRENT_LIST_DIR}/src)
|
||||
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)
|
||||
|
||||
add_executable (aot-analyzer src/main.cc src/aot_file.cc src/binary_file.cc src/option_parser.cc src/wasm_file.cc ${UNCOMMON_SHARED_SOURCE})
|
||||
|
||||
target_link_libraries (aot-analyzer vmlib -lm -ldl -lpthread -lrt)
|
55
test-tools/aot-analyzer/README.md
Normal file
55
test-tools/aot-analyzer/README.md
Normal file
|
@ -0,0 +1,55 @@
|
|||
# AoT-Analyzer: The AoT Binary analysis tool
|
||||
|
||||
|
||||
## Cloning
|
||||
|
||||
Clone as normal:
|
||||
|
||||
```console
|
||||
$ git clone
|
||||
$ cd aot-analyzer
|
||||
```
|
||||
|
||||
## Building using CMake directly
|
||||
|
||||
You'll need [CMake](https://cmake.org). You can then run CMake, the normal way:
|
||||
|
||||
```console
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake ..
|
||||
$ cmake --build .
|
||||
```
|
||||
|
||||
To analyze AoT files with GC feature enabled, you need to enable GC feature when compiling this tool:
|
||||
|
||||
```console
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake -DWAMR_BUILD_GC=1 ..
|
||||
$ cmake --build .
|
||||
```
|
||||
|
||||
## Running aot-analyzer
|
||||
|
||||
Some examples:
|
||||
|
||||
```sh
|
||||
# parse example.aot, and print basic information about AoT file
|
||||
$ ./aot-analyzer -i example.aot
|
||||
|
||||
# parse example.aot, and print the size of text section of the AoT file
|
||||
$ ./aot-analyzer -t example.aot
|
||||
|
||||
# compare these two files, and show the difference in function size between them
|
||||
$ ./aot-analyzer -c example.aot example.wasm
|
||||
```
|
||||
|
||||
**NOTE**: Using `-c` for file comparison, must ensure that the AoT file is generated based on this Wasm file.
|
||||
|
||||
|
||||
You can use `--help` to get additional help:
|
||||
|
||||
```console
|
||||
$ ./aot-analyzer --help
|
||||
```
|
52
test-tools/aot-analyzer/include/analyzer_error.h
Normal file
52
test-tools/aot-analyzer/include/analyzer_error.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef ANALYZER_ERROR_H_
|
||||
#define ANALYZER_ERROR_H_
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
namespace analyzer {
|
||||
|
||||
enum class ErrorLevel {
|
||||
Warning,
|
||||
Error,
|
||||
};
|
||||
|
||||
static inline const char *
|
||||
GetErrorLevelName(ErrorLevel error_level)
|
||||
{
|
||||
switch (error_level) {
|
||||
case ErrorLevel::Warning:
|
||||
return "warning";
|
||||
case ErrorLevel::Error:
|
||||
return "error";
|
||||
}
|
||||
ANALYZER_UNREACHABLE;
|
||||
}
|
||||
|
||||
class Error
|
||||
{
|
||||
public:
|
||||
Error()
|
||||
: error_level_(ErrorLevel::Error)
|
||||
{}
|
||||
Error(ErrorLevel error_level, std::string_view message)
|
||||
: error_level_(error_level)
|
||||
, message_(message)
|
||||
{}
|
||||
|
||||
ErrorLevel error_level_;
|
||||
std::string message_;
|
||||
};
|
||||
|
||||
using Errors = std::vector<Error>;
|
||||
|
||||
} // namespace analyzer
|
||||
#endif
|
32
test-tools/aot-analyzer/include/aot_file.h
Normal file
32
test-tools/aot-analyzer/include/aot_file.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef AOT_FILE_H_
|
||||
#define AOT_FILE_H_
|
||||
|
||||
#include "binary_file.h"
|
||||
|
||||
namespace analyzer {
|
||||
|
||||
class AoTFile : public BinaryFile
|
||||
{
|
||||
public:
|
||||
AoTFile(const char *file_name);
|
||||
|
||||
Result Scan();
|
||||
|
||||
Result ParseTargetInfo();
|
||||
AOTTargetInfo GetTargetInfo();
|
||||
|
||||
std::string GetBinTypeName(uint16_t bin_type);
|
||||
std::string GetExectuionTypeName(uint16_t e_type);
|
||||
std::string GetExectuionMachineName(uint16_t e_machine);
|
||||
|
||||
private:
|
||||
AOTTargetInfo target_info_;
|
||||
};
|
||||
|
||||
} // namespace analyzer
|
||||
#endif
|
67
test-tools/aot-analyzer/include/binary_file.h
Normal file
67
test-tools/aot-analyzer/include/binary_file.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef BINARY_FILE_H_
|
||||
#define BINARY_FILE_H_
|
||||
|
||||
#include "aot_runtime.h"
|
||||
#include "bh_read_file.h"
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "wasm_export.h"
|
||||
|
||||
namespace analyzer {
|
||||
|
||||
class BinaryFile
|
||||
{
|
||||
public:
|
||||
BinaryFile(const char *file_name);
|
||||
~BinaryFile();
|
||||
|
||||
Result ReadModule();
|
||||
|
||||
virtual Result Scan();
|
||||
|
||||
void ANALYZER_PRINTF_FORMAT(2, 3) PrintError(const char *format, ...);
|
||||
Result UpdateCurrentPos(uint32_t steps);
|
||||
|
||||
const char *GetFileName() { return file_name_; }
|
||||
uint8_t *GetFileData() { return file_data_; }
|
||||
uint32_t GetFileSize() { return file_size_; }
|
||||
size_t GetCurrentPos() { return current_pos_; }
|
||||
wasm_module_t GetModule() { return module_; }
|
||||
WASMModuleMemConsumption GetMemConsumption() { return mem_conspn_; }
|
||||
|
||||
private:
|
||||
const char *file_name_;
|
||||
uint8_t *file_data_;
|
||||
uint32_t file_size_;
|
||||
size_t current_pos_;
|
||||
wasm_module_t module_;
|
||||
WASMModuleMemConsumption mem_conspn_;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Result
|
||||
ReadT(T *out_value, BinaryFile *file, const char *type_name)
|
||||
{
|
||||
if (file == NULL
|
||||
|| file->GetCurrentPos() + sizeof(T) > file->GetFileSize()) {
|
||||
return Result::Error;
|
||||
}
|
||||
#if WAMR_BIG_ENDIAN
|
||||
uint8_t tmp[sizeof(T)];
|
||||
memcpy(tmp, file->GetFileData() + file->GetCurrentPos(), sizeof(tmp));
|
||||
SwapBytesSized(tmp, sizeof(tmp));
|
||||
memcpy(out_value, tmp, sizeof(T));
|
||||
#else
|
||||
memcpy(out_value, file->GetFileData() + file->GetCurrentPos(), sizeof(T));
|
||||
#endif
|
||||
file->UpdateCurrentPos(sizeof(T));
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
} // namespace analyzer
|
||||
#endif
|
100
test-tools/aot-analyzer/include/common.h
Normal file
100
test-tools/aot-analyzer/include/common.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef COMMON_H_
|
||||
#define COMMON_H_
|
||||
|
||||
#include "string_format.h"
|
||||
|
||||
#define ANALYZER_FATAL(...) fprintf(stderr, __VA_ARGS__), exit(1)
|
||||
|
||||
#if WITH_EXCEPTIONS
|
||||
#define ANALYZER_TRY try {
|
||||
#define ANALYZER_CATCH_BAD_ALLOC \
|
||||
} \
|
||||
catch (std::bad_alloc &) {}
|
||||
#define ANALYZER_CATCH_BAD_ALLOC_AND_EXIT \
|
||||
} \
|
||||
catch (std::bad_alloc &) { ANALYZER_FATAL("Memory allocation failure.\n"); }
|
||||
#else
|
||||
#define ANALYZER_TRY
|
||||
#define ANALYZER_CATCH_BAD_ALLOC
|
||||
#define ANALYZER_CATCH_BAD_ALLOC_AND_EXIT
|
||||
#endif
|
||||
|
||||
namespace analyzer {
|
||||
|
||||
struct ObjdumpOptions {
|
||||
bool info;
|
||||
bool text_size;
|
||||
bool details;
|
||||
bool compare;
|
||||
const char *file_name;
|
||||
};
|
||||
|
||||
struct Result {
|
||||
enum Enum {
|
||||
Ok,
|
||||
Error,
|
||||
};
|
||||
|
||||
Result()
|
||||
: Result(Ok)
|
||||
{}
|
||||
Result(Enum e)
|
||||
: enum_(e)
|
||||
{}
|
||||
operator Enum() const { return enum_; }
|
||||
Result &operator|=(Result rhs);
|
||||
|
||||
private:
|
||||
Enum enum_;
|
||||
};
|
||||
|
||||
inline Result
|
||||
operator|(Result lhs, Result rhs)
|
||||
{
|
||||
return (lhs == Result::Error || rhs == Result::Error) ? Result::Error
|
||||
: Result::Ok;
|
||||
}
|
||||
|
||||
inline Result &
|
||||
Result::operator|=(Result rhs)
|
||||
{
|
||||
enum_ = *this | rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline bool
|
||||
Succeeded(Result result)
|
||||
{
|
||||
return result == Result::Ok;
|
||||
}
|
||||
|
||||
inline bool
|
||||
Failed(Result result)
|
||||
{
|
||||
return result == Result::Error;
|
||||
}
|
||||
|
||||
#define CHECK_RESULT(expr) \
|
||||
do { \
|
||||
if (Failed(expr)) { \
|
||||
return Result::Error; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ERROR_IF(expr, ...) \
|
||||
do { \
|
||||
if (expr) { \
|
||||
PrintError(__VA_ARGS__); \
|
||||
return Result::Error; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ERROR_UNLESS(expr, ...) ERROR_IF(!(expr), __VA_ARGS__)
|
||||
|
||||
} // namespace analyzer
|
||||
#endif
|
168
test-tools/aot-analyzer/include/config.h
Normal file
168
test-tools/aot-analyzer/include/config.h
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_H_
|
||||
#define CONFIG_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define ANALYZER_VERSION_STRING "1.0.0"
|
||||
|
||||
#define WASM_MAGIC_NUMBER 0x6d736100
|
||||
#define WASM_CURRENT_VERSION 1
|
||||
|
||||
#define AOT_MAGIC_NUMBER 0x746f6100
|
||||
#define AOT_CURRENT_VERSION 3
|
||||
|
||||
/* Legal values for bin_type */
|
||||
#define BIN_TYPE_ELF32L 0 /* 32-bit little endian */
|
||||
#define BIN_TYPE_ELF32B 1 /* 32-bit big endian */
|
||||
#define BIN_TYPE_ELF64L 2 /* 64-bit little endian */
|
||||
#define BIN_TYPE_ELF64B 3 /* 64-bit big endian */
|
||||
#define BIN_TYPE_COFF32 4 /* 32-bit little endian */
|
||||
#define BIN_TYPE_COFF64 6 /* 64-bit little endian */
|
||||
|
||||
/* Legal values for e_type (object file type). */
|
||||
#define E_TYPE_NONE 0 /* No file type */
|
||||
#define E_TYPE_REL 1 /* Relocatable file */
|
||||
#define E_TYPE_EXEC 2 /* Executable file */
|
||||
#define E_TYPE_DYN 3 /* Shared object file */
|
||||
#define E_TYPE_XIP 4 /* eXecute In Place file */
|
||||
|
||||
/* Legal values for e_machine (architecture). */
|
||||
#define E_MACHINE_386 3 /* Intel 80386 */
|
||||
#define E_MACHINE_MIPS 8 /* MIPS R3000 big-endian */
|
||||
#define E_MACHINE_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
|
||||
#define E_MACHINE_ARM 40 /* ARM/Thumb */
|
||||
#define E_MACHINE_AARCH64 183 /* AArch64 */
|
||||
#define E_MACHINE_ARC 45 /* Argonaut RISC Core */
|
||||
#define E_MACHINE_IA_64 50 /* Intel Merced */
|
||||
#define E_MACHINE_MIPS_X 51 /* Stanford MIPS-X */
|
||||
#define E_MACHINE_X86_64 62 /* AMD x86-64 architecture */
|
||||
#define E_MACHINE_ARC_COMPACT 93 /* ARC International ARCompact */
|
||||
#define E_MACHINE_ARC_COMPACT2 195 /* Synopsys ARCompact V2 */
|
||||
#define E_MACHINE_XTENSA 94 /* Tensilica Xtensa Architecture */
|
||||
#define E_MACHINE_RISCV 243 /* RISC-V 32/64 */
|
||||
#define E_MACHINE_WIN_I386 0x14c /* Windows i386 architecture */
|
||||
#define E_MACHINE_WIN_X86_64 0x8664 /* Windows x86-64 architecture */
|
||||
|
||||
/* Whether <alloca.h> is available */
|
||||
#define HAVE_ALLOCA_H 1
|
||||
|
||||
/* Whether snprintf is defined by stdio.h */
|
||||
#define HAVE_SNPRINTF 1
|
||||
|
||||
/* Whether ssize_t is defined by stddef.h */
|
||||
#define HAVE_SSIZE_T 1
|
||||
|
||||
/* Whether strcasecmp is defined by strings.h */
|
||||
#define HAVE_STRCASECMP 1
|
||||
|
||||
#define COMPILER_IS_CLANG 0
|
||||
#define COMPILER_IS_GNU 1
|
||||
#define COMPILER_IS_MSVC 0
|
||||
|
||||
#define WITH_EXCEPTIONS 0
|
||||
|
||||
#define SIZEOF_SIZE_T 8
|
||||
|
||||
#if HAVE_ALLOCA_H
|
||||
#include <alloca.h>
|
||||
#elif COMPILER_IS_MSVC
|
||||
#include <malloc.h>
|
||||
#define alloca _alloca
|
||||
#elif defined(__MINGW32__)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#if COMPILER_IS_CLANG || COMPILER_IS_GNU
|
||||
|
||||
#if __MINGW32__
|
||||
#define ANALYZER_PRINTF_FORMAT(format_arg, first_arg) \
|
||||
__attribute__((format(gnu_printf, (format_arg), (first_arg))))
|
||||
#else
|
||||
#define ANALYZER_PRINTF_FORMAT(format_arg, first_arg) \
|
||||
__attribute__((format(printf, (format_arg), (first_arg))))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define ANALYZER_STATIC_ASSERT(x) static_assert((x), #x)
|
||||
#else
|
||||
#define ANALYZER_STATIC_ASSERT(x) _Static_assert((x), #x)
|
||||
#endif
|
||||
|
||||
#elif COMPILER_IS_MSVC
|
||||
|
||||
#include <intrin.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ANALYZER_STATIC_ASSERT(x) _STATIC_ASSERT(x)
|
||||
#define ANALYZER_PRINTF_FORMAT(format_arg, first_arg)
|
||||
|
||||
#else
|
||||
|
||||
#error unknown compiler
|
||||
|
||||
#endif
|
||||
|
||||
#define ANALYZER_UNREACHABLE abort()
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#if COMPILER_IS_MSVC
|
||||
|
||||
#elif COMPILER_IS_CLANG || COMPILER_IS_GNU
|
||||
|
||||
/* print format specifier for size_t */
|
||||
#define PRIzd "zd"
|
||||
#define PRIzx "zx"
|
||||
|
||||
#else
|
||||
|
||||
#error unknown compiler
|
||||
|
||||
#endif
|
||||
|
||||
#if HAVE_SNPRINTF
|
||||
#define analyzer_snprintf snprintf
|
||||
#elif COMPILER_IS_MSVC
|
||||
#include <cstdarg>
|
||||
int
|
||||
analyzer_snprintf(char *str, size_t size, const char *format, ...);
|
||||
#else
|
||||
#error no snprintf
|
||||
#endif
|
||||
|
||||
#if COMPILER_IS_MSVC
|
||||
int
|
||||
analyzer_vsnprintf(char *str, size_t size, const char *format, va_list ap);
|
||||
#else
|
||||
#define analyzer_vsnprintf vsnprintf
|
||||
#endif
|
||||
|
||||
#if !HAVE_SSIZE_T
|
||||
#if COMPILER_IS_MSVC
|
||||
#if defined(_WIN64)
|
||||
typedef signed __int64 ssize_t;
|
||||
#else
|
||||
typedef signed int ssize_t;
|
||||
#endif
|
||||
#else
|
||||
typedef long ssize_t;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !HAVE_STRCASECMP
|
||||
#if COMPILER_IS_MSVC
|
||||
#define strcasecmp _stricmp
|
||||
#else
|
||||
#error no strcasecmp
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
78
test-tools/aot-analyzer/include/option_parser.h
Normal file
78
test-tools/aot-analyzer/include/option_parser.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef OPTION_PARSER_H_
|
||||
#define OPTION_PARSER_H_
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
namespace analyzer {
|
||||
|
||||
class OptionParser
|
||||
{
|
||||
public:
|
||||
enum class HasArgument { No, Yes };
|
||||
enum class ArgumentCount { One, OneOrMore, ZeroOrMore };
|
||||
|
||||
struct Option;
|
||||
using Callback = std::function<void(const char *)>;
|
||||
using NullCallback = std::function<void()>;
|
||||
|
||||
struct Option {
|
||||
Option(char short_name, const std::string &long_name,
|
||||
const std::string &metavar, HasArgument has_argument,
|
||||
const std::string &help, const Callback &);
|
||||
|
||||
char short_name;
|
||||
std::string long_name;
|
||||
std::string metavar;
|
||||
bool has_argument;
|
||||
std::string help;
|
||||
Callback callback;
|
||||
};
|
||||
|
||||
struct Argument {
|
||||
Argument(const std::string &name, ArgumentCount, const Callback &);
|
||||
|
||||
std::string name;
|
||||
ArgumentCount count;
|
||||
Callback callback;
|
||||
int handled_count = 0;
|
||||
};
|
||||
|
||||
explicit OptionParser(const char *program_name, const char *description);
|
||||
|
||||
void AddOption(const Option &);
|
||||
void AddOption(char short_name, const char *long_name, const char *help,
|
||||
const NullCallback &);
|
||||
void AddOption(const char *long_name, const char *help,
|
||||
const NullCallback &);
|
||||
void AddOption(char short_name, const char *long_name, const char *metavar,
|
||||
const char *help, const Callback &);
|
||||
|
||||
void AddArgument(const std::string &name, ArgumentCount, const Callback &);
|
||||
void SetErrorCallback(const Callback &);
|
||||
void Parse(int argc, char *argv[]);
|
||||
void PrintHelp();
|
||||
|
||||
private:
|
||||
static int Match(const char *s, const std::string &full, bool has_argument);
|
||||
void ANALYZER_PRINTF_FORMAT(2, 3) Errorf(const char *format, ...);
|
||||
void HandleArgument(size_t *arg_index, const char *arg_value);
|
||||
void DefaultError(const std::string &);
|
||||
|
||||
std::string program_name_;
|
||||
std::string description_;
|
||||
std::vector<Option> options_;
|
||||
std::vector<Argument> arguments_;
|
||||
Callback on_error_;
|
||||
};
|
||||
|
||||
} // namespace analyzer
|
||||
#endif
|
56
test-tools/aot-analyzer/include/string_format.h
Normal file
56
test-tools/aot-analyzer/include/string_format.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef STRING_FORMAT_H_
|
||||
#define STRING_FORMAT_H_
|
||||
|
||||
#include <cstdarg>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define PRIstringview "%.*s"
|
||||
#define ANALYZER_PRINTF_STRING_VIEW_ARG(x) \
|
||||
static_cast<int>((x).length()), (x).data()
|
||||
|
||||
#define PRItypecode "%s%#x"
|
||||
|
||||
#define ANALYZER_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE 128
|
||||
#define ANALYZER_SNPRINTF_ALLOCA(buffer, len, format) \
|
||||
va_list args; \
|
||||
va_list args_copy; \
|
||||
va_start(args, format); \
|
||||
va_copy(args_copy, args); \
|
||||
char fixed_buf[ANALYZER_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE]; \
|
||||
char *buffer = fixed_buf; \
|
||||
size_t len = \
|
||||
analyzer_vsnprintf(fixed_buf, sizeof(fixed_buf), format, args); \
|
||||
va_end(args); \
|
||||
if (len + 1 > sizeof(fixed_buf)) { \
|
||||
buffer = static_cast<char *>(alloca(len + 1)); \
|
||||
len = analyzer_vsnprintf(buffer, len + 1, format, args_copy); \
|
||||
} \
|
||||
va_end(args_copy)
|
||||
|
||||
namespace analyzer {
|
||||
|
||||
inline std::string ANALYZER_PRINTF_FORMAT(1, 2)
|
||||
StringPrintf(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_list args_copy;
|
||||
va_start(args, format);
|
||||
va_copy(args_copy, args);
|
||||
size_t len = analyzer_vsnprintf(nullptr, 0, format, args) + 1;
|
||||
std::vector<char> buffer(len);
|
||||
va_end(args);
|
||||
analyzer_vsnprintf(buffer.data(), len, format, args_copy);
|
||||
va_end(args_copy);
|
||||
return std::string(buffer.data(), len - 1);
|
||||
}
|
||||
|
||||
} // namespace analyzer
|
||||
#endif
|
22
test-tools/aot-analyzer/include/wasm_file.h
Normal file
22
test-tools/aot-analyzer/include/wasm_file.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#ifndef WASM_FILE_H_
|
||||
#define WASM_FILE_H_
|
||||
|
||||
#include "binary_file.h"
|
||||
|
||||
namespace analyzer {
|
||||
|
||||
class WasmFile : public BinaryFile
|
||||
{
|
||||
public:
|
||||
WasmFile(const char *file_name);
|
||||
|
||||
Result Scan();
|
||||
};
|
||||
|
||||
} // namespace analyzer
|
||||
#endif
|
259
test-tools/aot-analyzer/src/aot_file.cc
Normal file
259
test-tools/aot-analyzer/src/aot_file.cc
Normal file
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "aot_file.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "analyzer_error.h"
|
||||
#include "common.h"
|
||||
|
||||
namespace analyzer {
|
||||
|
||||
AoTFile::AoTFile(const char *file_name)
|
||||
: BinaryFile(file_name)
|
||||
{
|
||||
memset(&target_info_, 0, sizeof(AOTTargetInfo));
|
||||
}
|
||||
|
||||
Result
|
||||
AoTFile::Scan()
|
||||
{
|
||||
CHECK_RESULT(ParseTargetInfo());
|
||||
WASMModuleMemConsumption mem_conspn = GetMemConsumption();
|
||||
aot_get_module_mem_consumption((AOTModule *)GetModule(), &mem_conspn);
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
Result
|
||||
AoTFile::ParseTargetInfo()
|
||||
{
|
||||
uint32_t section_id = 0;
|
||||
uint32_t section_size = 0;
|
||||
// skip AOT_MAGIC_NUMBER + AOT_CURRENT_VERSION
|
||||
UpdateCurrentPos(sizeof(uint32_t) + sizeof(uint32_t));
|
||||
|
||||
ReadT(§ion_id, this, "uint32_t");
|
||||
ReadT(§ion_size, this, "uint32_t");
|
||||
|
||||
// bin type
|
||||
uint16_t bin_type = 0;
|
||||
CHECK_RESULT(ReadT(&bin_type, this, "uint16_t"));
|
||||
target_info_.bin_type = bin_type;
|
||||
|
||||
// abi type
|
||||
uint16_t abi_type = 0;
|
||||
CHECK_RESULT(ReadT(&abi_type, this, "uint16_t"));
|
||||
target_info_.abi_type = abi_type;
|
||||
|
||||
// exectuion type
|
||||
uint16_t e_type = 0;
|
||||
CHECK_RESULT(ReadT(&e_type, this, "uint16_t"));
|
||||
target_info_.e_type = e_type;
|
||||
|
||||
// exectuion machine
|
||||
uint16_t e_machine = 0;
|
||||
CHECK_RESULT(ReadT(&e_machine, this, "uint16_t"));
|
||||
target_info_.e_machine = e_machine;
|
||||
|
||||
// exectuion version
|
||||
uint32_t e_version = 0;
|
||||
CHECK_RESULT(ReadT(&e_version, this, "uint32_t"));
|
||||
target_info_.e_version = e_version;
|
||||
|
||||
// exectuion flags
|
||||
uint32_t e_flags = 0;
|
||||
CHECK_RESULT(ReadT(&e_flags, this, "uint32_t"));
|
||||
target_info_.e_flags = e_flags;
|
||||
|
||||
// feature flags
|
||||
uint64_t feature_flags = 0;
|
||||
CHECK_RESULT(ReadT(&feature_flags, this, "uint64_t"));
|
||||
target_info_.feature_flags = feature_flags;
|
||||
|
||||
// reserved
|
||||
uint64_t reserved = 0;
|
||||
CHECK_RESULT(ReadT(&reserved, this, "uint64_t"));
|
||||
target_info_.reserved = reserved;
|
||||
|
||||
// Arch name
|
||||
const uint32_t section_end =
|
||||
section_size - (GetCurrentPos() - sizeof(uint32_t) - sizeof(uint32_t));
|
||||
for (size_t i = 0; i < section_end; ++i) {
|
||||
ReadT(&target_info_.arch[i], this, "uint8_t");
|
||||
}
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
AOTTargetInfo
|
||||
AoTFile::GetTargetInfo()
|
||||
{
|
||||
return target_info_;
|
||||
}
|
||||
|
||||
std::string
|
||||
AoTFile::GetBinTypeName(uint16_t bin_type)
|
||||
{
|
||||
std::string name = "";
|
||||
switch (bin_type) {
|
||||
case BIN_TYPE_ELF32L:
|
||||
{
|
||||
name = "ELF32L";
|
||||
break;
|
||||
}
|
||||
case BIN_TYPE_ELF32B:
|
||||
{
|
||||
name = "ELF32B";
|
||||
break;
|
||||
}
|
||||
case BIN_TYPE_ELF64L:
|
||||
{
|
||||
name = "ELF64L";
|
||||
break;
|
||||
}
|
||||
case BIN_TYPE_ELF64B:
|
||||
{
|
||||
name = "ELF64B";
|
||||
break;
|
||||
}
|
||||
case BIN_TYPE_COFF32:
|
||||
{
|
||||
name = "COFF32";
|
||||
break;
|
||||
}
|
||||
case BIN_TYPE_COFF64:
|
||||
{
|
||||
name = "COFF64";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
name = "bad bin type";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string
|
||||
AoTFile::GetExectuionTypeName(uint16_t e_type)
|
||||
{
|
||||
std::string name = "";
|
||||
switch (e_type) {
|
||||
case E_TYPE_NONE:
|
||||
{
|
||||
name = "NONE";
|
||||
break;
|
||||
}
|
||||
case E_TYPE_REL:
|
||||
{
|
||||
name = "REL";
|
||||
break;
|
||||
}
|
||||
case E_TYPE_EXEC:
|
||||
{
|
||||
name = "EXEC";
|
||||
break;
|
||||
}
|
||||
case E_TYPE_DYN:
|
||||
{
|
||||
name = "DYN";
|
||||
break;
|
||||
}
|
||||
case E_TYPE_XIP:
|
||||
{
|
||||
name = "XIP";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
name = "bad exectuion type";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string
|
||||
AoTFile::GetExectuionMachineName(uint16_t e_machine)
|
||||
{
|
||||
std::string machine = "";
|
||||
switch (e_machine) {
|
||||
case E_MACHINE_386:
|
||||
{
|
||||
machine = "386";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_MIPS:
|
||||
{
|
||||
machine = "MIPS";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_MIPS_RS3_LE:
|
||||
{
|
||||
machine = "MIPS_RS3_LE";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_ARM:
|
||||
{
|
||||
machine = "ARM";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_AARCH64:
|
||||
{
|
||||
machine = "AARCH64";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_ARC:
|
||||
{
|
||||
machine = "ARC";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_IA_64:
|
||||
{
|
||||
machine = "IA_64";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_MIPS_X:
|
||||
{
|
||||
machine = "MIPS_X";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_X86_64:
|
||||
{
|
||||
machine = "X86_64";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_ARC_COMPACT:
|
||||
{
|
||||
machine = "ARC_COMPACT";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_ARC_COMPACT2:
|
||||
{
|
||||
machine = "ARC_COMPACT2";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_XTENSA:
|
||||
{
|
||||
machine = "XTENSA";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_RISCV:
|
||||
{
|
||||
machine = "RISCV";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_WIN_I386:
|
||||
{
|
||||
machine = "WIN_I386";
|
||||
break;
|
||||
}
|
||||
case E_MACHINE_WIN_X86_64:
|
||||
{
|
||||
machine = "WIN_X86_64";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
machine = "bad exectuion machine type";
|
||||
}
|
||||
return machine;
|
||||
}
|
||||
|
||||
} // namespace analyzer
|
115
test-tools/aot-analyzer/src/binary_file.cc
Normal file
115
test-tools/aot-analyzer/src/binary_file.cc
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "binary_file.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
|
||||
#include "analyzer_error.h"
|
||||
|
||||
#if HAVE_ALLOCA
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
namespace analyzer {
|
||||
|
||||
BinaryFile::BinaryFile(const char *file_name)
|
||||
: file_name_(file_name)
|
||||
, file_data_(NULL)
|
||||
, file_size_(0)
|
||||
, current_pos_(0)
|
||||
, module_(NULL)
|
||||
{
|
||||
memset(&mem_conspn_, 0, sizeof(WASMModuleMemConsumption));
|
||||
}
|
||||
|
||||
BinaryFile::~BinaryFile()
|
||||
{
|
||||
if (module_) {
|
||||
wasm_runtime_unload(module_);
|
||||
wasm_runtime_free(file_data_);
|
||||
wasm_runtime_destroy();
|
||||
}
|
||||
}
|
||||
|
||||
Result
|
||||
BinaryFile::ReadModule()
|
||||
{
|
||||
char error_buf[128];
|
||||
|
||||
#if WASM_ENABLE_GC != 0
|
||||
uint32_t gc_heap_size = GC_HEAP_SIZE_DEFAULT;
|
||||
#endif
|
||||
|
||||
uint32_t buf_size, stack_size = DEFAULT_WASM_STACK_SIZE,
|
||||
heap_size = GC_HEAP_SIZE_DEFAULT;
|
||||
|
||||
RuntimeInitArgs init_args;
|
||||
memset(&init_args, 0, sizeof(RuntimeInitArgs));
|
||||
|
||||
#if WASM_ENABLE_GLOBAL_HEAP_POOL != 0
|
||||
static char global_heap_buf[WASM_GLOBAL_HEAP_SIZE] = { 0 };
|
||||
init_args.mem_alloc_type = Alloc_With_Pool;
|
||||
init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
|
||||
init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);
|
||||
#else
|
||||
init_args.mem_alloc_type = Alloc_With_Allocator;
|
||||
init_args.mem_alloc_option.allocator.malloc_func = (void *)malloc;
|
||||
init_args.mem_alloc_option.allocator.realloc_func = (void *)realloc;
|
||||
init_args.mem_alloc_option.allocator.free_func = (void *)free;
|
||||
#endif
|
||||
|
||||
/* initialize runtime environment */
|
||||
if (!wasm_runtime_full_init(&init_args)) {
|
||||
printf("Init runtime environment failed.\n");
|
||||
return Result::Error;
|
||||
}
|
||||
|
||||
file_data_ = (uint8 *)bh_read_file_to_buffer(file_name_, &file_size_);
|
||||
if (!file_data_) {
|
||||
printf("Open Binary file [%s] failed.\n", file_name_);
|
||||
wasm_runtime_destroy();
|
||||
return Result::Error;
|
||||
}
|
||||
|
||||
module_ =
|
||||
wasm_runtime_load(file_data_, file_size_, error_buf, sizeof(error_buf));
|
||||
if (!module_) {
|
||||
printf("Load Binary module failed. error: %s\n", error_buf);
|
||||
wasm_runtime_free(file_data_);
|
||||
wasm_runtime_destroy();
|
||||
return Result::Error;
|
||||
}
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
Result
|
||||
BinaryFile::Scan()
|
||||
{
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
void ANALYZER_PRINTF_FORMAT(2, 3) BinaryFile::PrintError(const char *format,
|
||||
...)
|
||||
{
|
||||
ErrorLevel error_level = ErrorLevel::Error;
|
||||
ANALYZER_SNPRINTF_ALLOCA(buffer, length, format);
|
||||
Error error(error_level, buffer);
|
||||
fprintf(stderr, "%07" PRIzx ": %s: %s\n", current_pos_,
|
||||
GetErrorLevelName(error_level), buffer);
|
||||
}
|
||||
|
||||
Result
|
||||
BinaryFile::UpdateCurrentPos(uint32_t steps)
|
||||
{
|
||||
if (current_pos_ + steps > file_size_) {
|
||||
return Result::Error;
|
||||
}
|
||||
current_pos_ += steps;
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
} // namespace analyzer
|
663
test-tools/aot-analyzer/src/main.cc
Normal file
663
test-tools/aot-analyzer/src/main.cc
Normal file
|
@ -0,0 +1,663 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "aot_file.h"
|
||||
#include "common.h"
|
||||
#include "option_parser.h"
|
||||
#include "wasm_file.h"
|
||||
|
||||
using namespace analyzer;
|
||||
|
||||
static const char s_description[] =
|
||||
R"( Print information about the contents of AoT binaries.
|
||||
|
||||
examples:
|
||||
$ aot-analyzer example.aot
|
||||
)";
|
||||
|
||||
struct func_info {
|
||||
uint32_t idx;
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
static int
|
||||
compare_func_ptrs(const void *f1, const void *f2)
|
||||
{
|
||||
return (intptr_t)((struct func_info *)f1)->ptr
|
||||
- (intptr_t)((struct func_info *)f2)->ptr;
|
||||
}
|
||||
|
||||
static struct func_info *
|
||||
sort_func_ptrs(const AOTModule *module)
|
||||
{
|
||||
uint64_t content_len;
|
||||
struct func_info *sorted_func_ptrs;
|
||||
unsigned i;
|
||||
|
||||
content_len = (uint64_t)sizeof(struct func_info) * module->func_count;
|
||||
sorted_func_ptrs = (struct func_info *)wasm_runtime_malloc(content_len);
|
||||
if (!sorted_func_ptrs) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < module->func_count; i++) {
|
||||
sorted_func_ptrs[i].idx = i;
|
||||
sorted_func_ptrs[i].ptr = module->func_ptrs[i];
|
||||
}
|
||||
|
||||
qsort(sorted_func_ptrs, module->func_count, sizeof(struct func_info),
|
||||
compare_func_ptrs);
|
||||
return sorted_func_ptrs;
|
||||
}
|
||||
|
||||
static ObjdumpOptions s_objdump_options;
|
||||
|
||||
static std::vector<const char *> s_infiles;
|
||||
|
||||
static void
|
||||
ParseOptions(int argc, char **argv)
|
||||
{
|
||||
OptionParser parser("aot-analyzer", s_description);
|
||||
|
||||
parser.AddOption('i', "info", "Print basic information about AoT",
|
||||
[]() { s_objdump_options.info = true; });
|
||||
parser.AddOption('t', "text-size", "Print text size",
|
||||
[]() { s_objdump_options.text_size = true; });
|
||||
parser.AddOption('x', "details", "Show AoT details",
|
||||
[]() { s_objdump_options.details = true; });
|
||||
parser.AddOption('c', "compare",
|
||||
"Show the differences between AoT and WASM",
|
||||
[]() { s_objdump_options.compare = true; });
|
||||
parser.AddArgument(
|
||||
"filename", OptionParser::ArgumentCount::OneOrMore,
|
||||
[](const char *argument) { s_infiles.push_back(argument); });
|
||||
parser.Parse(argc, argv);
|
||||
}
|
||||
|
||||
void
|
||||
InitStdio()
|
||||
{
|
||||
#if COMPILER_IS_MSVC
|
||||
int result = _setmode(_fileno(stdout), _O_BINARY);
|
||||
if (result == -1) {
|
||||
perror("Cannot set mode binary to stdout");
|
||||
}
|
||||
result = _setmode(_fileno(stderr), _O_BINARY);
|
||||
if (result == -1) {
|
||||
perror("Cannot set mode binary to stderr");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
dump_value_type(uint8 type)
|
||||
{
|
||||
switch (type) {
|
||||
case VALUE_TYPE_I32:
|
||||
printf("i32");
|
||||
break;
|
||||
case VALUE_TYPE_I64:
|
||||
printf("i64");
|
||||
break;
|
||||
case VALUE_TYPE_F32:
|
||||
printf("f32");
|
||||
break;
|
||||
case VALUE_TYPE_F64:
|
||||
printf("f64");
|
||||
break;
|
||||
case VALUE_TYPE_V128:
|
||||
printf("v128");
|
||||
break;
|
||||
case PACKED_TYPE_I8:
|
||||
printf("i8");
|
||||
break;
|
||||
case PACKED_TYPE_I16:
|
||||
printf("i16");
|
||||
break;
|
||||
case REF_TYPE_FUNCREF:
|
||||
printf("funcref");
|
||||
break;
|
||||
case REF_TYPE_EXTERNREF:
|
||||
printf("externref");
|
||||
break;
|
||||
case REF_TYPE_ANYREF:
|
||||
printf("anyref");
|
||||
break;
|
||||
case REF_TYPE_EQREF:
|
||||
printf("eqref");
|
||||
break;
|
||||
case REF_TYPE_I31REF:
|
||||
printf("i31ref");
|
||||
break;
|
||||
case REF_TYPE_STRUCTREF:
|
||||
printf("structref");
|
||||
break;
|
||||
case REF_TYPE_ARRAYREF:
|
||||
printf("arrayref");
|
||||
break;
|
||||
case REF_TYPE_NULLREF:
|
||||
printf("nullref");
|
||||
break;
|
||||
case REF_TYPE_NULLFUNCREF:
|
||||
printf("nullfuncref");
|
||||
break;
|
||||
case REF_TYPE_NULLEXTERNREF:
|
||||
printf("nullexternref");
|
||||
break;
|
||||
default:
|
||||
printf("unknown");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DumpInfo(AoTFile *aot)
|
||||
{
|
||||
const AOTTargetInfo target_info = aot->GetTargetInfo();
|
||||
printf("AOT File Information:\n\n");
|
||||
printf("Binary type: %s\n",
|
||||
aot->GetBinTypeName(target_info.bin_type).c_str());
|
||||
printf("ABI type: %d\n", target_info.abi_type);
|
||||
printf("Exectuion type: %s\n",
|
||||
aot->GetExectuionTypeName(target_info.e_type).c_str());
|
||||
printf("Exectuion machine: %s\n",
|
||||
aot->GetExectuionMachineName(target_info.e_machine).c_str());
|
||||
printf("Exectuion version: %u\n", target_info.e_version);
|
||||
printf("Exectuion flags: %u\n", target_info.e_flags);
|
||||
printf("Feature flags: %ld\n", target_info.feature_flags);
|
||||
printf("Reserved: %ld\n", target_info.reserved);
|
||||
printf("Arch: %s\n", target_info.arch);
|
||||
}
|
||||
|
||||
void
|
||||
DumpTextSize(AoTFile *aot)
|
||||
{
|
||||
const AOTTargetInfo target_info = aot->GetTargetInfo();
|
||||
printf("%s: file format <%s>\n\n", aot->GetFileName(),
|
||||
aot->GetBinTypeName(target_info.bin_type).c_str());
|
||||
printf("Text size:\n");
|
||||
|
||||
const uint32_t literal_size =
|
||||
((AOTModule *)(aot->GetModule()))->literal_size;
|
||||
const uint32_t code_size = ((AOTModule *)(aot->GetModule()))->code_size;
|
||||
printf(" literal size= %u Bytes\n", literal_size);
|
||||
printf(" code size= %u Bytes\n", code_size);
|
||||
}
|
||||
|
||||
void
|
||||
DumpDetails(AoTFile *aot)
|
||||
{
|
||||
const AOTTargetInfo target_info = aot->GetTargetInfo();
|
||||
printf("%s: file format <%s>\n\n", aot->GetFileName(),
|
||||
aot->GetBinTypeName(target_info.bin_type).c_str());
|
||||
printf("Details:\n\n");
|
||||
|
||||
// Types
|
||||
const uint32_t type_count = ((AOTModule *)(aot->GetModule()))->type_count;
|
||||
AOTType **types = ((AOTModule *)(aot->GetModule()))->types;
|
||||
printf("Types[%u]\n", type_count);
|
||||
#if WASM_ENABLE_GC != 0
|
||||
const char *wasm_type[] = { "function", "struct", "array" };
|
||||
for (uint32_t index = 0; index < type_count; index++) {
|
||||
AOTType *type = types[index];
|
||||
const uint16_t type_flag = type->type_flag;
|
||||
printf(" -[%u] ", index);
|
||||
if (type_flag == WASM_TYPE_FUNC) {
|
||||
wasm_dump_func_type(((AOTFuncType *)type));
|
||||
}
|
||||
else if (type_flag == WASM_TYPE_STRUCT) {
|
||||
wasm_dump_struct_type(((AOTStructType *)type));
|
||||
}
|
||||
else if (type_flag == WASM_TYPE_ARRAY) {
|
||||
wasm_dump_array_type(((AOTArrayType *)type));
|
||||
}
|
||||
else {
|
||||
printf(" -[%u] unknown type\n", index);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (uint32_t index = 0; index < type_count; index++) {
|
||||
printf(" -[%u] ", index);
|
||||
AOTType *type = types[index];
|
||||
uint32_t i = 0;
|
||||
printf("func [");
|
||||
|
||||
for (i = 0; i < type->param_count; i++) {
|
||||
dump_value_type(type->types[i]);
|
||||
if (i < (uint32)type->param_count - 1)
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
printf("] -> [");
|
||||
|
||||
for (; i < (uint32)(type->param_count + type->result_count); i++) {
|
||||
dump_value_type(type->types[i]);
|
||||
if (i < (uint32)type->param_count + type->result_count - 1)
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
printf("]\n");
|
||||
}
|
||||
#endif
|
||||
printf("\n\n");
|
||||
|
||||
// Imports
|
||||
const uint32_t import_memory_count =
|
||||
((AOTModule *)(aot->GetModule()))->import_memory_count;
|
||||
AOTImportMemory *import_memories =
|
||||
((AOTModule *)(aot->GetModule()))->import_memories;
|
||||
const uint32_t import_table_count =
|
||||
((AOTModule *)(aot->GetModule()))->import_table_count;
|
||||
AOTImportTable *import_tables =
|
||||
((AOTModule *)(aot->GetModule()))->import_tables;
|
||||
const uint32_t import_global_count =
|
||||
((AOTModule *)(aot->GetModule()))->import_global_count;
|
||||
AOTImportGlobal *import_globals =
|
||||
((AOTModule *)(aot->GetModule()))->import_globals;
|
||||
const uint32_t import_func_count =
|
||||
((AOTModule *)(aot->GetModule()))->import_func_count;
|
||||
AOTImportFunc *import_funcs =
|
||||
((AOTModule *)(aot->GetModule()))->import_funcs;
|
||||
printf("Imports[%u]\n", import_memory_count + import_table_count
|
||||
+ import_global_count + import_func_count);
|
||||
|
||||
// import memories
|
||||
printf(" -import_memories[%u]\n", import_memory_count);
|
||||
for (uint32_t index = 0; index < import_memory_count; index++) {
|
||||
AOTImportMemory memory = import_memories[index];
|
||||
printf(" -[%u] num_bytes_per_page:%5u init_page_count:%5u "
|
||||
"max_page_count:%5u module_name: %s memory_name: %s\n",
|
||||
index, memory.num_bytes_per_page, memory.mem_init_page_count,
|
||||
memory.mem_max_page_count, memory.module_name,
|
||||
memory.memory_name);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// import tables
|
||||
printf(" -import_tables[%u]\n", import_table_count);
|
||||
for (uint32_t index = 0; index < import_table_count; index++) {
|
||||
AOTImportTable table = import_tables[index];
|
||||
printf(" -[%u] ", index);
|
||||
printf("elem_type: ");
|
||||
#if WASM_ENABLE_GC != 0
|
||||
wasm_dump_value_type(table.elem_type, table.elem_ref_type);
|
||||
#else
|
||||
dump_value_type(table.elem_type);
|
||||
#endif
|
||||
printf(" init_size:%5u max_size:%5u "
|
||||
"module_name: %s table_name: %s\n",
|
||||
table.table_init_size, table.table_max_size, table.module_name,
|
||||
table.table_name);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// import globals
|
||||
printf(" -import_globals[%u]\n", import_global_count);
|
||||
for (uint32_t index = 0; index < import_global_count; index++) {
|
||||
AOTImportGlobal global = import_globals[index];
|
||||
printf(" -[%u] ", index);
|
||||
printf("type: ");
|
||||
dump_value_type(global.type);
|
||||
printf(" module_name: %s global_name: %s\n", global.module_name,
|
||||
global.global_name);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// import functions
|
||||
printf(" -import_functions[%u]\n", import_func_count);
|
||||
for (uint32_t index = 0; index < import_func_count; index++) {
|
||||
AOTImportFunc func = import_funcs[index];
|
||||
printf(" -[%u] module_name: %s function_name: %s\n", index,
|
||||
func.module_name, func.func_name);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
// Functions
|
||||
const uint32_t func_count = ((AOTModule *)(aot->GetModule()))->func_count;
|
||||
const uint32_t code_size = ((AOTModule *)(aot->GetModule()))->code_size;
|
||||
struct func_info *sorted_func_ptrs = NULL;
|
||||
sorted_func_ptrs = sort_func_ptrs(((AOTModule *)(aot->GetModule())));
|
||||
|
||||
if (sorted_func_ptrs) {
|
||||
printf("Function[%u]\n", func_count);
|
||||
for (uint32_t index = 0; index < func_count; index++) {
|
||||
const uint32_t func_size =
|
||||
index + 1 < func_count
|
||||
? (uintptr_t)(sorted_func_ptrs[index + 1].ptr)
|
||||
- (uintptr_t)(sorted_func_ptrs[index].ptr)
|
||||
: code_size
|
||||
+ (uintptr_t)(((AOTModule *)(aot->GetModule()))->code)
|
||||
- (uintptr_t)(sorted_func_ptrs[index].ptr);
|
||||
printf(" -[%u] code_size= %u Bytes\n", index, func_size);
|
||||
}
|
||||
wasm_runtime_free(sorted_func_ptrs);
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
// Tables
|
||||
const uint32_t table_count = ((AOTModule *)(aot->GetModule()))->table_count;
|
||||
AOTTable *tables = ((AOTModule *)(aot->GetModule()))->tables;
|
||||
printf("Tables[%u]\n", table_count);
|
||||
for (uint32_t index = 0; index < table_count; index++) {
|
||||
AOTTable table = tables[index];
|
||||
printf(" -[%u] ", index);
|
||||
printf("elem_type: ");
|
||||
#if WASM_ENABLE_GC != 0
|
||||
wasm_dump_value_type(table.elem_type, table.elem_ref_type);
|
||||
#else
|
||||
dump_value_type(table.elem_type);
|
||||
#endif
|
||||
printf(" init_size:%5u max_size:%5u\n", table.table_init_size,
|
||||
table.table_max_size);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
// Memories
|
||||
const uint32_t memory_count =
|
||||
((AOTModule *)(aot->GetModule()))->memory_count;
|
||||
AOTMemory *memories = ((AOTModule *)(aot->GetModule()))->memories;
|
||||
printf("Memories[%u]\n", memory_count);
|
||||
|
||||
for (uint32_t index = 0; index < memory_count; index++) {
|
||||
AOTMemory memory = memories[index];
|
||||
printf(" -[%u] memory_flags:%5u bytes_per_page:%5u "
|
||||
"init_page_count:%5u max_page_count:%5u\n",
|
||||
index, memory.memory_flags, memory.num_bytes_per_page,
|
||||
memory.mem_init_page_count, memory.mem_max_page_count);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
// Globals
|
||||
const uint32_t global_count =
|
||||
((AOTModule *)(aot->GetModule()))->global_count;
|
||||
AOTGlobal *globals = ((AOTModule *)(aot->GetModule()))->globals;
|
||||
printf("Globals[%u]\n", global_count);
|
||||
|
||||
for (uint32_t index = 0; index < global_count; index++) {
|
||||
AOTGlobal global = globals[index];
|
||||
printf(" -[%u] ", index);
|
||||
printf("type: ");
|
||||
dump_value_type(global.type);
|
||||
printf(" is_mutable: %d size: %u data_offset: %u\n",
|
||||
global.is_mutable, global.size, global.data_offset);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
// Exports
|
||||
const uint32_t export_count =
|
||||
((AOTModule *)(aot->GetModule()))->export_count;
|
||||
AOTExport *exports = ((AOTModule *)(aot->GetModule()))->exports;
|
||||
printf("Exports[%u]\n", export_count);
|
||||
|
||||
for (uint32_t index = 0; index < export_count; index++) {
|
||||
AOTExport expt = exports[index];
|
||||
printf(" -[%u] kind:%5d index:%5u name: %s\n", index, expt.kind,
|
||||
expt.index, expt.name);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
// Code
|
||||
const uint32_t aot_code_size = (aot->GetMemConsumption()).aot_code_size;
|
||||
const uint32_t literal_size =
|
||||
((AOTModule *)(aot->GetModule()))->literal_size;
|
||||
const uint32_t data_section_count =
|
||||
((AOTModule *)(aot->GetModule()))->data_section_count;
|
||||
|
||||
printf("Codes[%u]\n", aot_code_size);
|
||||
printf(" -code\n");
|
||||
printf(" -code_size: %u Bytes\n", code_size);
|
||||
printf("\n");
|
||||
printf(" -literal\n");
|
||||
printf(" -literal_size: %u Bytes\n", literal_size);
|
||||
printf("\n");
|
||||
printf(" -data section\n");
|
||||
for (uint32_t index = 0; index < data_section_count; index++) {
|
||||
AOTObjectDataSection *obj_data =
|
||||
((AOTModule *)(aot->GetModule()))->data_sections + index;
|
||||
printf(" -[%u] code_size:%5u Bytes name: %s\n", index,
|
||||
obj_data->size, obj_data->name);
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void
|
||||
DumpCompare(AoTFile *aot, WasmFile *wasm)
|
||||
{
|
||||
const AOTTargetInfo target_info = aot->GetTargetInfo();
|
||||
AOTModule *aot_module = (AOTModule *)(aot->GetModule());
|
||||
WASMModuleMemConsumption aot_mem_conspn = aot->GetMemConsumption();
|
||||
|
||||
WASMModule *wasm_module = (WASMModule *)(wasm->GetModule());
|
||||
|
||||
const uint32_t aot_func_count = aot_module->func_count;
|
||||
const uint32_t aot_code_size = aot_module->code_size;
|
||||
struct func_info *sorted_func_ptrs = NULL;
|
||||
sorted_func_ptrs = sort_func_ptrs(((AOTModule *)(aot->GetModule())));
|
||||
if (!sorted_func_ptrs) {
|
||||
printf("sort AoT functions failed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t wasm_func_count = wasm_module->function_count;
|
||||
WASMFunction **wasm_functions = wasm_module->functions;
|
||||
|
||||
if (aot_func_count != wasm_func_count) {
|
||||
printf("The number of AoT functions does not match the number of Wasm "
|
||||
"functions.\n");
|
||||
wasm_runtime_free(sorted_func_ptrs);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t wasm_code_size = 0;
|
||||
// print function Comparison Details
|
||||
printf(
|
||||
"|--------------------------------------------------------------------"
|
||||
"-------------------|\n");
|
||||
printf(
|
||||
"| Function Code Size Compare "
|
||||
" |\n");
|
||||
printf(
|
||||
"|--------------------------------------------------------------------"
|
||||
"-------------------|\n");
|
||||
printf(
|
||||
"| ID | AoT Function Code Size | Wasm Function Code Size | "
|
||||
"expansion multiple |\n");
|
||||
printf(
|
||||
"|--------------------------------------------------------------------"
|
||||
"-------------------|\n");
|
||||
|
||||
for (uint32_t index = 0; index < aot_func_count; index++) {
|
||||
const uint32_t aot_func_size =
|
||||
index + 1 < aot_func_count
|
||||
? (uintptr_t)(sorted_func_ptrs[index + 1].ptr)
|
||||
- (uintptr_t)(sorted_func_ptrs[index].ptr)
|
||||
: aot_code_size + (uintptr_t)(aot_module->code)
|
||||
- (uintptr_t)(sorted_func_ptrs[index].ptr);
|
||||
const uint32_t wasm_func_size = wasm_functions[index]->code_size;
|
||||
wasm_code_size += wasm_func_size;
|
||||
printf(
|
||||
"| %4d | %10d Bytes | %10d Bytes | %10.2f "
|
||||
" "
|
||||
" |\n",
|
||||
index, aot_func_size, wasm_func_size,
|
||||
(aot_func_size * 1.0) / wasm_func_size);
|
||||
printf(
|
||||
"|-----------------------------------------------------------------"
|
||||
"-"
|
||||
"---------------------|\n");
|
||||
}
|
||||
wasm_runtime_free(sorted_func_ptrs);
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
printf(
|
||||
"|--------------------------------------------------------------------"
|
||||
"---|\n");
|
||||
printf(
|
||||
"| Total Code Size Compare "
|
||||
" |\n");
|
||||
printf(
|
||||
"|--------------------------------------------------------------------"
|
||||
"---|\n");
|
||||
printf("| AoT code size= %10d Bytes | Wasm code size= %10d Bytes |\n",
|
||||
aot_code_size, wasm_code_size);
|
||||
printf(
|
||||
"|--------------------------------------------------------------------"
|
||||
"---|\n");
|
||||
}
|
||||
|
||||
int
|
||||
ProgramMain(int argc, char **argv)
|
||||
{
|
||||
InitStdio();
|
||||
|
||||
ParseOptions(argc, argv);
|
||||
if (!s_objdump_options.info && !s_objdump_options.text_size
|
||||
&& !s_objdump_options.details && !s_objdump_options.compare) {
|
||||
fprintf(stderr,
|
||||
"At least one of the following switches must be given:\n");
|
||||
fprintf(stderr, " -i/ --info\n");
|
||||
fprintf(stderr, " -t/ --text-size\n");
|
||||
fprintf(stderr, " -x/ --details\n");
|
||||
fprintf(stderr, " -c/ --compare\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::vector<BinaryFile *> readers;
|
||||
for (const char *filename : s_infiles) {
|
||||
BinaryFile *reader = NULL;
|
||||
const char *dot = strrchr(filename, '.');
|
||||
if (!dot) {
|
||||
printf("bad file name: %s\n", filename);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(dot, ".aot", 4) == 0) {
|
||||
reader = new AoTFile(filename);
|
||||
}
|
||||
else if (strncmp(dot, ".wasm", 4) == 0) {
|
||||
reader = new WasmFile(filename);
|
||||
}
|
||||
else {
|
||||
printf("unkown file extension: %s\n", dot);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (reader && reader->ReadModule() == Result::Error) {
|
||||
printf("read module failed.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
CHECK_RESULT(reader->Scan());
|
||||
readers.push_back(reader);
|
||||
}
|
||||
|
||||
// -i/ --info
|
||||
if (s_objdump_options.info == 1) {
|
||||
for (size_t i = 0; i < readers.size(); ++i) {
|
||||
printf("\n");
|
||||
|
||||
BinaryFile *reader = readers[i];
|
||||
const uint32_t module_type = reader->GetModule()->module_type;
|
||||
if (module_type == Wasm_Module_AoT) {
|
||||
AoTFile *aot = dynamic_cast<AoTFile *>(reader);
|
||||
if (!aot) {
|
||||
printf("[DumpInfo]: Reader cast failed.\n");
|
||||
continue;
|
||||
}
|
||||
DumpInfo(aot);
|
||||
}
|
||||
else {
|
||||
printf("[DumpInfo]: Wrong file format, not an AoT file.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -t/ --text-size
|
||||
if (s_objdump_options.text_size == 1) {
|
||||
for (size_t i = 0; i < readers.size(); ++i) {
|
||||
printf("\n");
|
||||
|
||||
BinaryFile *reader = readers[i];
|
||||
const uint32_t module_type = reader->GetModule()->module_type;
|
||||
if (module_type == Wasm_Module_AoT) {
|
||||
AoTFile *aot = dynamic_cast<AoTFile *>(reader);
|
||||
if (!aot) {
|
||||
printf("[DumpTextSize]: Reader cast failed.\n");
|
||||
continue;
|
||||
}
|
||||
DumpTextSize(aot);
|
||||
}
|
||||
else {
|
||||
printf("[DumpTextSize]: Wrong file format, not an AoT file.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -x/ --details
|
||||
if (s_objdump_options.details == 1) {
|
||||
for (size_t i = 0; i < readers.size(); ++i) {
|
||||
printf("\n");
|
||||
|
||||
BinaryFile *reader = readers[i];
|
||||
const uint32_t module_type = reader->GetModule()->module_type;
|
||||
if (module_type == Wasm_Module_AoT) {
|
||||
AoTFile *aot = dynamic_cast<AoTFile *>(reader);
|
||||
if (!aot) {
|
||||
printf("[DumpDetails]: Reader cast failed.\n");
|
||||
continue;
|
||||
}
|
||||
DumpDetails(aot);
|
||||
}
|
||||
else {
|
||||
printf("[DumpDetails]: Wrong file format, not an AoT file.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -c/ --compare
|
||||
if (s_objdump_options.compare == 1) {
|
||||
printf("\n");
|
||||
|
||||
if (readers.size() != 2) {
|
||||
printf("[DumpCompare]: Illegal number of file parameters.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
AoTFile *aot = NULL;
|
||||
WasmFile *wasm = NULL;
|
||||
for (size_t i = 0; i < readers.size(); ++i) {
|
||||
BinaryFile *reader = readers[i];
|
||||
const uint32_t module_type = reader->GetModule()->module_type;
|
||||
if (module_type == Wasm_Module_AoT) {
|
||||
aot = dynamic_cast<AoTFile *>(reader);
|
||||
}
|
||||
else if (module_type == Wasm_Module_Bytecode) {
|
||||
wasm = dynamic_cast<WasmFile *>(reader);
|
||||
}
|
||||
}
|
||||
if (!aot) {
|
||||
printf("[DumpCompare]: an aot file is required for comparison.\n");
|
||||
return 1;
|
||||
}
|
||||
if (!wasm) {
|
||||
printf("[DumpCompare]: a wasm file is required for comparison.\n");
|
||||
return 1;
|
||||
}
|
||||
DumpCompare(aot, wasm);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
ANALYZER_TRY
|
||||
return ProgramMain(argc, argv);
|
||||
ANALYZER_CATCH_BAD_ALLOC_AND_EXIT
|
||||
}
|
345
test-tools/aot-analyzer/src/option_parser.cc
Normal file
345
test-tools/aot-analyzer/src/option_parser.cc
Normal file
|
@ -0,0 +1,345 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "option_parser.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "string_format.h"
|
||||
|
||||
namespace analyzer {
|
||||
|
||||
OptionParser::Option::Option(char short_name, const std::string &long_name,
|
||||
const std::string &metavar,
|
||||
HasArgument has_argument, const std::string &help,
|
||||
const Callback &callback)
|
||||
: short_name(short_name)
|
||||
, long_name(long_name)
|
||||
, metavar(metavar)
|
||||
, has_argument(has_argument == HasArgument::Yes)
|
||||
, help(help)
|
||||
, callback(callback)
|
||||
{}
|
||||
|
||||
OptionParser::Argument::Argument(const std::string &name, ArgumentCount count,
|
||||
const Callback &callback)
|
||||
: name(name)
|
||||
, count(count)
|
||||
, callback(callback)
|
||||
{}
|
||||
|
||||
OptionParser::OptionParser(const char *program_name, const char *description)
|
||||
: program_name_(program_name)
|
||||
, description_(description)
|
||||
, on_error_([this](const std::string &message) { DefaultError(message); })
|
||||
{
|
||||
AddOption("help", "Print this help message", [this]() {
|
||||
PrintHelp();
|
||||
exit(0);
|
||||
});
|
||||
AddOption("version", "Print version information", []() {
|
||||
printf("%s\n", ANALYZER_VERSION_STRING);
|
||||
exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
OptionParser::AddOption(const Option &option)
|
||||
{
|
||||
options_.emplace_back(option);
|
||||
}
|
||||
|
||||
void
|
||||
OptionParser::AddArgument(const std::string &name, ArgumentCount count,
|
||||
const Callback &callback)
|
||||
{
|
||||
arguments_.emplace_back(name, count, callback);
|
||||
}
|
||||
|
||||
void
|
||||
OptionParser::AddOption(char short_name, const char *long_name,
|
||||
const char *help, const NullCallback &callback)
|
||||
{
|
||||
Option option(short_name, long_name, std::string(), HasArgument::No, help,
|
||||
[callback](const char *) { callback(); });
|
||||
AddOption(option);
|
||||
}
|
||||
|
||||
void
|
||||
OptionParser::AddOption(const char *long_name, const char *help,
|
||||
const NullCallback &callback)
|
||||
{
|
||||
Option option('\0', long_name, std::string(), HasArgument::No, help,
|
||||
[callback](const char *) { callback(); });
|
||||
AddOption(option);
|
||||
}
|
||||
|
||||
void
|
||||
OptionParser::AddOption(char short_name, const char *long_name,
|
||||
const char *metavar, const char *help,
|
||||
const Callback &callback)
|
||||
{
|
||||
Option option(short_name, long_name, metavar, HasArgument::Yes, help,
|
||||
callback);
|
||||
AddOption(option);
|
||||
}
|
||||
|
||||
void
|
||||
OptionParser::SetErrorCallback(const Callback &callback)
|
||||
{
|
||||
on_error_ = callback;
|
||||
}
|
||||
|
||||
int
|
||||
OptionParser::Match(const char *s, const std::string &full, bool has_argument)
|
||||
{
|
||||
int i;
|
||||
for (i = 0;; i++) {
|
||||
if (full[i] == '\0') {
|
||||
if (s[i] == '\0') {
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
if (!(has_argument && s[i] == '=')) {
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (s[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
if (s[i] != full[i]) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void
|
||||
OptionParser::Errorf(const char *format, ...)
|
||||
{
|
||||
ANALYZER_SNPRINTF_ALLOCA(buffer, length, format);
|
||||
std::string msg(program_name_);
|
||||
msg += ": ";
|
||||
msg += buffer;
|
||||
msg += "\nTry '--help' for more information.";
|
||||
on_error_(msg.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
OptionParser::DefaultError(const std::string &message)
|
||||
{
|
||||
ANALYZER_FATAL("%s\n", message.c_str());
|
||||
}
|
||||
|
||||
void
|
||||
OptionParser::HandleArgument(size_t *arg_index, const char *arg_value)
|
||||
{
|
||||
if (*arg_index >= arguments_.size()) {
|
||||
Errorf("unexpected argument '%s'", arg_value);
|
||||
return;
|
||||
}
|
||||
Argument &argument = arguments_[*arg_index];
|
||||
argument.callback(arg_value);
|
||||
argument.handled_count++;
|
||||
|
||||
if (argument.count == ArgumentCount::One) {
|
||||
(*arg_index)++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OptionParser::Parse(int argc, char *argv[])
|
||||
{
|
||||
size_t arg_index = 0;
|
||||
bool processing_options = true;
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
const char *arg = argv[i];
|
||||
if (!processing_options || arg[0] != '-') {
|
||||
HandleArgument(&arg_index, arg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (arg[1] == '-') {
|
||||
if (arg[2] == '\0') {
|
||||
processing_options = false;
|
||||
continue;
|
||||
}
|
||||
int best_index = -1;
|
||||
int best_length = 0;
|
||||
int best_count = 0;
|
||||
for (size_t j = 0; j < options_.size(); ++j) {
|
||||
const Option &option = options_[j];
|
||||
if (!option.long_name.empty()) {
|
||||
int match_length =
|
||||
Match(&arg[2], option.long_name, option.has_argument);
|
||||
if (match_length > best_length) {
|
||||
best_index = j;
|
||||
best_length = match_length;
|
||||
best_count = 1;
|
||||
}
|
||||
else if (match_length == best_length && best_length > 0) {
|
||||
best_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best_count > 1) {
|
||||
Errorf("ambiguous option '%s'", arg);
|
||||
continue;
|
||||
}
|
||||
else if (best_count == 0) {
|
||||
Errorf("unknown option '%s'", arg);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Option &best_option = options_[best_index];
|
||||
const char *option_argument = nullptr;
|
||||
if (best_option.has_argument) {
|
||||
if (arg[best_length + 1] != 0 && arg[best_length + 2] == '=') {
|
||||
option_argument = &arg[best_length + 3];
|
||||
}
|
||||
else {
|
||||
if (i + 1 == argc || argv[i + 1][0] == '-') {
|
||||
Errorf("option '--%s' requires argument",
|
||||
best_option.long_name.c_str());
|
||||
continue;
|
||||
}
|
||||
++i;
|
||||
option_argument = argv[i];
|
||||
}
|
||||
}
|
||||
best_option.callback(option_argument);
|
||||
}
|
||||
else {
|
||||
if (arg[1] == '\0') {
|
||||
HandleArgument(&arg_index, arg);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int k = 1; arg[k]; ++k) {
|
||||
bool matched = false;
|
||||
for (const Option &option : options_) {
|
||||
if (option.short_name && arg[k] == option.short_name) {
|
||||
const char *option_argument = nullptr;
|
||||
if (option.has_argument) {
|
||||
if (arg[k + 1] != '\0') {
|
||||
Errorf("option '-%c' requires argument",
|
||||
option.short_name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (i + 1 == argc || argv[i + 1][0] == '-') {
|
||||
Errorf("option '-%c' requires argument",
|
||||
option.short_name);
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
option_argument = argv[i];
|
||||
}
|
||||
option.callback(option_argument);
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!matched) {
|
||||
Errorf("unknown option '-%c'", arg[k]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!arguments_.empty() && arguments_.back().handled_count == 0) {
|
||||
for (size_t i = arg_index; i < arguments_.size(); ++i) {
|
||||
if (arguments_[i].count != ArgumentCount::ZeroOrMore) {
|
||||
Errorf("expected %s argument.", arguments_[i].name.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OptionParser::PrintHelp()
|
||||
{
|
||||
printf("usage: %s [options]", program_name_.c_str());
|
||||
|
||||
for (size_t i = 0; i < arguments_.size(); ++i) {
|
||||
Argument &argument = arguments_[i];
|
||||
switch (argument.count) {
|
||||
case ArgumentCount::One:
|
||||
printf(" %s", argument.name.c_str());
|
||||
break;
|
||||
|
||||
case ArgumentCount::OneOrMore:
|
||||
printf(" %s+", argument.name.c_str());
|
||||
break;
|
||||
|
||||
case ArgumentCount::ZeroOrMore:
|
||||
printf(" [%s]...", argument.name.c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
printf("%s\n", description_.c_str());
|
||||
printf("options:\n");
|
||||
|
||||
const size_t kExtraSpace = 8;
|
||||
size_t longest_name_length = 0;
|
||||
for (const Option &option : options_) {
|
||||
size_t length;
|
||||
if (!option.long_name.empty()) {
|
||||
length = option.long_name.size();
|
||||
if (!option.metavar.empty()) {
|
||||
length += option.metavar.size() + 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (length > longest_name_length) {
|
||||
longest_name_length = length;
|
||||
}
|
||||
}
|
||||
|
||||
for (const Option &option : options_) {
|
||||
if (!option.short_name && option.long_name.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
if (option.short_name) {
|
||||
line += std::string(" -") + option.short_name + ", ";
|
||||
}
|
||||
else {
|
||||
line += " ";
|
||||
}
|
||||
|
||||
std::string flag;
|
||||
if (!option.long_name.empty()) {
|
||||
flag = "--";
|
||||
if (!option.metavar.empty()) {
|
||||
flag += option.long_name + '=' + option.metavar;
|
||||
}
|
||||
else {
|
||||
flag += option.long_name;
|
||||
}
|
||||
}
|
||||
|
||||
size_t remaining = longest_name_length + kExtraSpace + 2 - flag.size();
|
||||
line += flag + std::string(remaining, ' ');
|
||||
|
||||
if (!option.help.empty()) {
|
||||
line += option.help;
|
||||
}
|
||||
printf("%s\n", line.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace analyzer
|
27
test-tools/aot-analyzer/src/wasm_file.cc
Normal file
27
test-tools/aot-analyzer/src/wasm_file.cc
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Xiaomi Corporation. All rights reserved.
|
||||
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
*/
|
||||
|
||||
#include "wasm_file.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "analyzer_error.h"
|
||||
#include "common.h"
|
||||
|
||||
namespace analyzer {
|
||||
|
||||
WasmFile::WasmFile(const char *file_name)
|
||||
: BinaryFile(file_name)
|
||||
{}
|
||||
|
||||
Result
|
||||
WasmFile::Scan()
|
||||
{
|
||||
WASMModuleMemConsumption mem_conspn = GetMemConsumption();
|
||||
wasm_get_module_mem_consumption((WASMModule *)GetModule(), &mem_conspn);
|
||||
return Result::Ok;
|
||||
}
|
||||
|
||||
} // namespace analyzer
|
Loading…
Reference in New Issue
Block a user