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:
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
|
||||
Reference in New Issue
Block a user