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:
GanJingSaiyan
2024-05-08 16:31:39 +08:00
committed by GitHub
parent 1c2a8fca4e
commit 07eae7c424
15 changed files with 2127 additions and 0 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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