From da1a9b36f553623ffdfd5f58870840352757e111 Mon Sep 17 00:00:00 2001 From: Konstantin Baladurin Date: Thu, 30 Sep 2021 01:46:48 +0300 Subject: [PATCH] Fix Method::GetLineNumFromBytecodeOffset Change-Id: I82a68723ef70c57ffc7dc015333860b242d0b57f Signed-off-by: Konstantin Baladurin --- CMakeLists.txt | 4 +- cmake/ark-third-party/miniz/CMakeLists.txt | 36 --- cmake/ark-third-party/zlib/CMakeLists.txt | 202 ++++++++++++++ libpandafile/debug_info_extractor.cpp | 288 ++++++++------------ libpandafile/file_items.h | 4 +- libpandafile/line_number_program.h | 291 +++++++++++++++++++++ libziparchive/CMakeLists.txt | 12 +- runtime/method.cpp | 169 ++++++++---- runtime/tests/method_test.cpp | 60 +++++ scripts/install-third-party | 6 +- 10 files changed, 797 insertions(+), 275 deletions(-) delete mode 100644 cmake/ark-third-party/miniz/CMakeLists.txt create mode 100644 cmake/ark-third-party/zlib/CMakeLists.txt create mode 100644 libpandafile/line_number_program.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f1c2615..f8f24f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,8 +169,8 @@ if(PANDA_WITH_TOOLCHAIN) add_subdirectory(${PANDA_THIRD_PARTY_CONFIG_DIR}/securec) add_subdirectory(libpandabase) - set(MINIZ_ROOT ${PANDA_THIRD_PARTY_SOURCES_DIR}/miniz/amalgamation) - add_subdirectory(${PANDA_THIRD_PARTY_CONFIG_DIR}/miniz) + set(ZLIB_ROOT ${PANDA_THIRD_PARTY_SOURCES_DIR}/zlib) + add_subdirectory(${PANDA_THIRD_PARTY_CONFIG_DIR}/zlib) add_subdirectory(libziparchive) add_subdirectory(libpandafile) diff --git a/cmake/ark-third-party/miniz/CMakeLists.txt b/cmake/ark-third-party/miniz/CMakeLists.txt deleted file mode 100644 index d00cab9..0000000 --- a/cmake/ark-third-party/miniz/CMakeLists.txt +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright (c) 2021-2022 Huawei Device Co., Ltd. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -project(miniz) - -add_library(miniz ${MINIZ_ROOT}/miniz.c) -target_include_directories(miniz PUBLIC ${MINIZ_ROOT}) - -target_compile_options(miniz PUBLIC -Wno-return-type-c-linkage) - -# NB! We always build miniz statically, but there seems -# no obvious reasons for that. If we reconsider, the logic -# below should be replaced with something like: -# -# add_library(miniz ${PANDA_DEFAULT_LIB_TYPE} miniz.c) -# -# **Besides** build of host tools should be fixed to -# take into account new shared library -if(NOT PANDA_TARGET_WINDOWS) - target_compile_options(miniz PRIVATE -fPIC) -endif() - -if (PANDA_ENABLE_AFL) - include("${PANDA_ROOT}/fuzzing/Fuzzing.cmake") - panda_substitute_libs(TARGET miniz) -endif() diff --git a/cmake/ark-third-party/zlib/CMakeLists.txt b/cmake/ark-third-party/zlib/CMakeLists.txt new file mode 100644 index 0000000..962be35 --- /dev/null +++ b/cmake/ark-third-party/zlib/CMakeLists.txt @@ -0,0 +1,202 @@ +cmake_minimum_required(VERSION 2.4.4) +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) + +project(zlib C) + +set(VERSION "1.2.11") + +option(ASM686 "Enable building i686 assembly implementation") +option(AMD64 "Enable building amd64 assembly implementation") + +set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables") +set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries") +set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers") +set(INSTALL_MAN_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Installation directory for manual pages") +set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") + +include(CheckTypeSize) +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckCSourceCompiles) +enable_testing() + +check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(stdint.h HAVE_STDINT_H) +check_include_file(stddef.h HAVE_STDDEF_H) + +# +# Check to see if we have large file support +# +set(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1) +# We add these other definitions here because CheckTypeSize.cmake +# in CMake 2.4.x does not automatically do so and we want +# compatibility with CMake 2.4.x. +if(HAVE_SYS_TYPES_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_TYPES_H) +endif() +if(HAVE_STDINT_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDINT_H) +endif() +if(HAVE_STDDEF_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDDEF_H) +endif() +check_type_size(off64_t OFF64_T) +if(HAVE_OFF64_T) + add_definitions(-D_LARGEFILE64_SOURCE=1) +endif() +set(CMAKE_REQUIRED_DEFINITIONS) # clear variable + +# +# Check for fseeko +# +check_function_exists(fseeko HAVE_FSEEKO) +if(NOT HAVE_FSEEKO) + add_definitions(-DNO_FSEEKO) +endif() + +# +# Check for unistd.h +# +check_include_file(unistd.h Z_HAVE_UNISTD_H) + +if(MSVC) + set(CMAKE_DEBUG_POSTFIX "d") + add_definitions(-D_CRT_SECURE_NO_DEPRECATE) + add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) + # If we're doing an out of source build and the user has a zconf.h + # in their source tree... + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h) + message(STATUS "Renaming") + message(STATUS " ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h") + message(STATUS "to 'zconf.h.included' because this file is included with zlib") + message(STATUS "but CMake generates it automatically in the build directory.") + file(RENAME ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.included) + endif() +endif() + +set(ZLIB_PC ${CMAKE_CURRENT_BINARY_DIR}/zlib.pc) +configure_file( ${PANDA_THIRD_PARTY_SOURCES_DIR}/zlib/zlib.pc.cmakein + ${ZLIB_PC} @ONLY) +configure_file( ${PANDA_THIRD_PARTY_SOURCES_DIR}/zlib/zconf.h.cmakein + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY) +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}) + + +#============================================================================ +# zlib +#============================================================================ + +set(ZLIB_PUBLIC_HDRS + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h + ${ZLIB_ROOT}/zlib.h +) +set(ZLIB_PRIVATE_HDRS + ${ZLIB_ROOT}/crc32.h + ${ZLIB_ROOT}/deflate.h + ${ZLIB_ROOT}/gzguts.h + ${ZLIB_ROOT}/inffast.h + ${ZLIB_ROOT}/inffixed.h + ${ZLIB_ROOT}/inflate.h + ${ZLIB_ROOT}/inftrees.h + ${ZLIB_ROOT}/trees.h + ${ZLIB_ROOT}/zutil.h +) +set(ZLIB_SRCS + ${ZLIB_ROOT}/adler32.c + ${ZLIB_ROOT}/compress.c + ${ZLIB_ROOT}/contrib/minizip/ioapi.c + ${ZLIB_ROOT}/contrib/minizip/unzip.c + ${ZLIB_ROOT}/contrib/minizip/zip.c + ${ZLIB_ROOT}/crc32.c + ${ZLIB_ROOT}/deflate.c + ${ZLIB_ROOT}/gzclose.c + ${ZLIB_ROOT}/gzlib.c + ${ZLIB_ROOT}/gzread.c + ${ZLIB_ROOT}/gzwrite.c + ${ZLIB_ROOT}/inflate.c + ${ZLIB_ROOT}/infback.c + ${ZLIB_ROOT}/inftrees.c + ${ZLIB_ROOT}/inffast.c + ${ZLIB_ROOT}/trees.c + ${ZLIB_ROOT}/uncompr.c + ${ZLIB_ROOT}/zutil.c +) + +if(NOT MINGW) + set(ZLIB_DLL_SRCS + ${ZLIB_ROOT}/win32/zlib1.rc # If present will override custom build rule below. + ) +endif() + +if(CMAKE_COMPILER_IS_GNUCC) + if(ASM686) + set(ZLIB_ASMS ${ZLIB_ROOT}/contrib/asm686/match.S) + elseif (AMD64) + set(ZLIB_ASMS ${ZLIB_ROOT}/contrib/amd64/amd64-match.S) + endif () + + if(ZLIB_ASMS) + add_definitions(-DASMV) + set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE) + endif() +endif() + +if(MSVC) + if(ASM686) + ENABLE_LANGUAGE(ASM_MASM) + set(ZLIB_ASMS + ${ZLIB_ROOT}/contrib/masmx86/inffas32.asm + ${ZLIB_ROOT}/contrib/masmx86/match686.asm + ) + elseif (AMD64) + ENABLE_LANGUAGE(ASM_MASM) + set(ZLIB_ASMS + ${ZLIB_ROOT}/contrib/masmx64/gvmat64.asm + ${ZLIB_ROOT}/contrib/masmx64/inffasx64.asm + ) + endif() + + if(ZLIB_ASMS) + add_definitions(-DASMV -DASMINF) + endif() +endif() + +# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION +file(READ ${PANDA_THIRD_PARTY_SOURCES_DIR}/zlib/zlib.h _zlib_h_contents) +string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*" + "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents}) + +add_library(zlib STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +target_include_directories(zlib PUBLIC ${ZLIB_ROOT}) + +target_compile_options(zlib PUBLIC -Wno-return-type-c-linkage) + +if(HOST_TOOLS) + set_target_properties(zlib + PROPERTIES + ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/third_party/zlib + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/third_party/zlib + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/third_party/zlib + ) +endif() + +# NB! We always build zlib statically, but there seems +# no obvious reasons for that. If we reconsider, the logic +# below should be replaced with something like: +# +# add_library(zlib ${PANDA_DEFAULT_LIB_TYPE} zlib.c) +# +# **Besides** build of host tools should be fixed to +# take into account new shared library +if(NOT PANDA_TARGET_WINDOWS) + target_compile_options(zlib PRIVATE -fPIC) +endif() + +if (PANDA_ENABLE_AFL) + include("${PANDA_ROOT}/fuzzing/Fuzzing.cmake") + panda_substitute_libs(TARGET zlib) +endif() diff --git a/libpandafile/debug_info_extractor.cpp b/libpandafile/debug_info_extractor.cpp index 7f2bf1f..792f4a1 100644 --- a/libpandafile/debug_info_extractor.cpp +++ b/libpandafile/debug_info_extractor.cpp @@ -14,7 +14,7 @@ */ #include "debug_info_extractor.h" -#include "line_program_state.h" +#include "line_number_program.h" #include "class_data_accessor-inl.h" #include "debug_data_accessor-inl.h" #include "utils/utf.h" @@ -31,93 +31,134 @@ DebugInfoExtractor::DebugInfoExtractor(const File *pf) Extract(pf); } -class LineNumberProgramProcessor { +class LineNumberProgramHandler { public: - LineNumberProgramProcessor(LineProgramState state, const uint8_t *program) : state_(state), program_(program) {} + explicit LineNumberProgramHandler(LineProgramState *state) : state_(state) {} + ~LineNumberProgramHandler() = default; - ~LineNumberProgramProcessor() = default; + NO_COPY_SEMANTIC(LineNumberProgramHandler); + NO_MOVE_SEMANTIC(LineNumberProgramHandler); - NO_COPY_SEMANTIC(LineNumberProgramProcessor); - NO_MOVE_SEMANTIC(LineNumberProgramProcessor); - - void Process() + LineProgramState *GetState() const + { + return state_; + } + + void ProcessBegin() + { + lnt_.push_back({state_->GetAddress(), state_->GetLine()}); + } + + void ProcessEnd() { - auto opcode = ReadOpcode(); - lnt_.push_back({state_.GetAddress(), state_.GetLine()}); - while (opcode != Opcode::END_SEQUENCE) { - switch (opcode) { - case Opcode::ADVANCE_LINE: { - HandleAdvanceLine(); - break; - } - case Opcode::ADVANCE_PC: { - HandleAdvancePc(); - break; - } - case Opcode::SET_FILE: { - HandleSetFile(); - break; - } - case Opcode::SET_SOURCE_CODE: { - HandleSetSourceCode(); - break; - } - case Opcode::SET_PROLOGUE_END: - case Opcode::SET_EPILOGUE_BEGIN: - break; - case Opcode::START_LOCAL: { - HandleStartLocal(); - break; - } - case Opcode::START_LOCAL_EXTENDED: { - HandleStartLocalExtended(); - break; - } - case Opcode::RESTART_LOCAL: { - LOG(FATAL, PANDAFILE) << "Opcode RESTART_LOCAL is not supported"; - break; - } - case Opcode::END_LOCAL: { - HandleEndLocal(); - break; - } - case Opcode::SET_COLUMN: { - HandleSetColumn(); - break; - } - default: { - HandleSpecialOpcode(opcode); - break; - } - } - opcode = ReadOpcode(); - } ProcessVars(); } + bool HandleAdvanceLine(int32_t line_diff) const + { + state_->AdvanceLine(line_diff); + return true; + } + + bool HandleAdvancePc(uint32_t pc_diff) const + { + state_->AdvancePc(pc_diff); + return true; + } + + bool HandleSetFile(uint32_t source_file_id) const + { + state_->SetFile(source_file_id); + return true; + } + + bool HandleSetSourceCode(uint32_t source_code_id) const + { + state_->SetSourceCode(source_code_id); + return true; + } + + bool HandleSetPrologueEnd() const + { + return true; + } + + bool HandleSetEpilogueBegin() const + { + return true; + } + + bool HandleStartLocal(int32_t reg_number, uint32_t name_id, uint32_t type_id) + { + const char *name = GetStringFromConstantPool(state_->GetPandaFile(), name_id); + const char *type = GetStringFromConstantPool(state_->GetPandaFile(), type_id); + lvt_.push_back({name, type, type, reg_number, state_->GetAddress(), 0}); + return true; + } + + bool HandleStartLocalExtended(int32_t reg_number, uint32_t name_id, uint32_t type_id, uint32_t type_signature_id) + { + const char *name = GetStringFromConstantPool(state_->GetPandaFile(), name_id); + const char *type = GetStringFromConstantPool(state_->GetPandaFile(), type_id); + const char *type_sign = GetStringFromConstantPool(state_->GetPandaFile(), type_signature_id); + lvt_.push_back({name, type, type_sign, reg_number, state_->GetAddress(), 0}); + return true; + } + + bool HandleEndLocal(int32_t reg_number) + { + bool found = false; + for (auto it = lvt_.rbegin(); it != lvt_.rend(); ++it) { + if (it->reg_number == reg_number) { + it->end_offset = state_->GetAddress(); + found = true; + break; + } + } + if (!found) { + LOG(FATAL, PANDAFILE) << "Unknown variable"; + } + return true; + } + + bool HandleSetColumn(int32_t column_number) + { + state_->SetColumn(column_number); + cnt_.push_back({state_->GetAddress(), state_->GetColumn()}); + return true; + } + + bool HandleSpecialOpcode(uint32_t pc_offset, int32_t line_offset) + { + state_->AdvancePc(pc_offset); + state_->AdvanceLine(line_offset); + lnt_.push_back({state_->GetAddress(), state_->GetLine()}); + return true; + } + LineNumberTable GetLineNumberTable() const { return lnt_; } - ColumnNumberTable GetColumnNumberTable() const - { - return cnt_; - } - LocalVariableTable GetLocalVariableTable() const { return lvt_; } + ColumnNumberTable GetColumnNumberTable() const + { + return cnt_; + } + const uint8_t *GetFile() const { - return state_.GetFile(); + return state_->GetFile(); } const uint8_t *GetSourceCode() const { - return state_.GetSourceCode(); + return state_->GetSourceCode(); } private: @@ -127,112 +168,12 @@ private: { for (auto &var : lvt_) { if (var.end_offset == 0) { - var.end_offset = state_.GetAddress(); + var.end_offset = state_->GetAddress(); } } } - Opcode ReadOpcode() - { - auto opcode = static_cast(*program_); - ++program_; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) - return opcode; - } - - int32_t ReadRegisterNumber() - { - auto [regiser_number, n, is_full] = leb128::DecodeSigned(program_); - LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; - program_ += n; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) - return regiser_number; - } - - void HandleAdvanceLine() - { - auto line_diff = state_.ReadSLeb128(); - state_.AdvanceLine(line_diff); - } - - void HandleAdvancePc() - { - auto pc_diff = state_.ReadULeb128(); - state_.AdvancePc(pc_diff); - } - - void HandleSetFile() - { - state_.SetFile(state_.ReadULeb128()); - } - - void HandleSetSourceCode() - { - state_.SetSourceCode(state_.ReadULeb128()); - } - - void HandleSetPrologueEnd() {} - - void HandleSetEpilogueBegin() {} - - void HandleStartLocal() - { - auto reg_number = ReadRegisterNumber(); - auto name_index = state_.ReadULeb128(); - auto type_index = state_.ReadULeb128(); - const char *name = GetStringFromConstantPool(state_.GetPandaFile(), name_index); - const char *type = GetStringFromConstantPool(state_.GetPandaFile(), type_index); - lvt_.push_back({name, type, type, reg_number, state_.GetAddress(), 0}); - } - - void HandleStartLocalExtended() - { - auto reg_number = ReadRegisterNumber(); - auto name_index = state_.ReadULeb128(); - auto type_index = state_.ReadULeb128(); - auto type_signature_index = state_.ReadULeb128(); - const char *name = GetStringFromConstantPool(state_.GetPandaFile(), name_index); - const char *type = GetStringFromConstantPool(state_.GetPandaFile(), type_index); - const char *type_sign = GetStringFromConstantPool(state_.GetPandaFile(), type_signature_index); - lvt_.push_back({name, type, type_sign, reg_number, state_.GetAddress(), 0}); - } - - void HandleEndLocal() - { - auto reg_number = ReadRegisterNumber(); - bool found = false; - for (auto it = lvt_.rbegin(); it != lvt_.rend(); ++it) { - if (it->reg_number == reg_number) { - it->end_offset = state_.GetAddress(); - found = true; - break; - } - } - if (!found) { - LOG(FATAL, PANDAFILE) << "Unknown variable"; - } - } - - void HandleSetColumn() - { - auto cn = state_.ReadULeb128(); - state_.SetColumn(cn); - cnt_.push_back({state_.GetAddress(), state_.GetColumn()}); - } - - void HandleSpecialOpcode(LineNumberProgramItem::Opcode opcode) - { - ASSERT(static_cast(opcode) >= LineNumberProgramItem::OPCODE_BASE); - - auto adjust_opcode = static_cast(static_cast(opcode) - LineNumberProgramItem::OPCODE_BASE); - auto pc_offset = static_cast(adjust_opcode / LineNumberProgramItem::LINE_RANGE); - int32_t line_offset = - static_cast(adjust_opcode) % LineNumberProgramItem::LINE_RANGE + LineNumberProgramItem::LINE_BASE; - state_.AdvancePc(pc_offset); - state_.AdvanceLine(line_offset); - lnt_.push_back({state_.GetAddress(), state_.GetLine()}); - } - - LineProgramState state_; - const uint8_t *program_; + LineProgramState *state_; LineNumberTable lnt_; LocalVariableTable lvt_; ColumnNumberTable cnt_; @@ -278,15 +219,16 @@ void DebugInfoExtractor::Extract(const File *pf) LineProgramState state(panda_file, source_file_id.value_or(File::EntityId(0)), dda.GetLineStart(), dda.GetConstantPool()); - LineNumberProgramProcessor program_processor(state, program); + LineNumberProgramHandler handler(&state); + LineNumberProgramProcessor program_processor(program, &handler); program_processor.Process(); File::EntityId method_id = mda.GetMethodId(); - const char *source_file = utf::Mutf8AsCString(program_processor.GetFile()); - const char *source_code = utf::Mutf8AsCString(program_processor.GetSourceCode()); - methods_.push_back({source_file, source_code, method_id, program_processor.GetLineNumberTable(), - program_processor.GetLocalVariableTable(), std::move(param_names), - program_processor.GetColumnNumberTable()}); + const char *source_file = utf::Mutf8AsCString(handler.GetFile()); + const char *source_code = utf::Mutf8AsCString(handler.GetSourceCode()); + methods_.push_back({source_file, source_code, method_id, handler.GetLineNumberTable(), + handler.GetLocalVariableTable(), std::move(param_names), + handler.GetColumnNumberTable()}); }); } } diff --git a/libpandafile/file_items.h b/libpandafile/file_items.h index e3d5147..d49bbdc 100644 --- a/libpandafile/file_items.h +++ b/libpandafile/file_items.h @@ -489,8 +489,8 @@ public: SET_EPILOGUE_BEGIN = 0x08, SET_FILE = 0x09, SET_SOURCE_CODE = 0x0a, - SET_COLUMN = 0X0b, // The SET_COLUMN opcode takes a single unsigned LEB128 operand and - // stores it in the column register of the state machine. + SET_COLUMN = 0X0b, // The SET_COLUMN opcode takes a single unsigned LEB128 operand and + // stores it in the column register of the state machine. LAST }; diff --git a/libpandafile/line_number_program.h b/libpandafile/line_number_program.h new file mode 100644 index 0000000..36504b0 --- /dev/null +++ b/libpandafile/line_number_program.h @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LIBPANDAFILE_LINE_NUMBER_PROGRAM_H +#define LIBPANDAFILE_LINE_NUMBER_PROGRAM_H + +#include "file-inl.h" +#include "file_items.h" + +namespace panda::panda_file { + +class LineProgramState { +public: + LineProgramState(const File &pf, File::EntityId file, size_t line, Span constant_pool) + : pf_(pf), file_(file), line_(line), constant_pool_(constant_pool) + { + } + + void AdvanceLine(int32_t v) + { + line_ += v; + } + + void AdvancePc(uint32_t v) + { + address_ += v; + } + + void SetFile(uint32_t offset) + { + file_ = File::EntityId(offset); + } + + const uint8_t *GetFile() const + { + return pf_.GetStringData(file_).data; + } + + bool HasFile() const + { + return file_.IsValid(); + } + + void SetSourceCode(uint32_t offset) + { + source_code_ = File::EntityId(offset); + } + + const uint8_t *GetSourceCode() const + { + return pf_.GetStringData(source_code_).data; + } + + bool HasSourceCode() const + { + return source_code_.IsValid(); + } + + size_t GetLine() const + { + return line_; + } + + void SetColumn(int32_t c) + { + column_ = c; + } + + size_t GetColumn() const + { + return column_; + } + + uint32_t GetAddress() const + { + return address_; + } + + uint32_t ReadULeb128() + { + return panda_file::helpers::ReadULeb128(&constant_pool_); + } + + int32_t ReadSLeb128() + { + return panda_file::helpers::ReadLeb128(&constant_pool_); + } + + const File &GetPandaFile() const + { + return pf_; + } + +private: + const File &pf_; + + File::EntityId file_; + File::EntityId source_code_; + size_t line_; + size_t column_ {0}; + Span constant_pool_; + + uint32_t address_ {0}; +}; + +template +class LineNumberProgramProcessor { +public: + LineNumberProgramProcessor(const uint8_t *program, Handler *handler) + : state_(handler->GetState()), program_(program), handler_(handler) + { + } + + ~LineNumberProgramProcessor() = default; + + NO_COPY_SEMANTIC(LineNumberProgramProcessor); + NO_MOVE_SEMANTIC(LineNumberProgramProcessor); + + // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE) + void Process() + { + handler_->ProcessBegin(); + + auto opcode = ReadOpcode(); + bool res = false; + while (opcode != Opcode::END_SEQUENCE) { + switch (opcode) { + case Opcode::ADVANCE_LINE: { + res = HandleAdvanceLine(); + break; + } + case Opcode::ADVANCE_PC: { + res = HandleAdvancePc(); + break; + } + case Opcode::SET_FILE: { + res = HandleSetFile(); + break; + } + case Opcode::SET_SOURCE_CODE: { + res = HandleSetSourceCode(); + break; + } + case Opcode::SET_PROLOGUE_END: + case Opcode::SET_EPILOGUE_BEGIN: + break; + case Opcode::START_LOCAL: { + res = HandleStartLocal(); + break; + } + case Opcode::START_LOCAL_EXTENDED: { + res = HandleStartLocalExtended(); + break; + } + case Opcode::RESTART_LOCAL: { + LOG(FATAL, PANDAFILE) << "Opcode RESTART_LOCAL is not supported"; + break; + } + case Opcode::END_LOCAL: { + res = HandleEndLocal(); + break; + } + case Opcode::SET_COLUMN: { + HandleSetColumn(); + break; + } + default: { + res = HandleSpecialOpcode(opcode); + break; + } + } + + if (!res) { + break; + } + + opcode = ReadOpcode(); + } + + handler_->ProcessEnd(); + } + +private: + using Opcode = LineNumberProgramItem::Opcode; + + Opcode ReadOpcode() + { + auto opcode = static_cast(*program_); + ++program_; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + return opcode; + } + + int32_t ReadRegisterNumber() + { + auto [regiser_number, n, is_full] = leb128::DecodeSigned(program_); + LOG_IF(!is_full, FATAL, COMMON) << "Cannot read a register number"; + program_ += n; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + return regiser_number; + } + + bool HandleAdvanceLine() const + { + auto line_diff = state_->ReadSLeb128(); + return handler_->HandleAdvanceLine(line_diff); + } + + bool HandleAdvancePc() const + { + auto pc_diff = state_->ReadULeb128(); + return handler_->HandleAdvancePc(pc_diff); + } + + bool HandleSetFile() const + { + return handler_->HandleSetFile(state_->ReadULeb128()); + } + + bool HandleSetSourceCode() const + { + return handler_->HandleSetSourceCode(state_->ReadULeb128()); + } + + bool HandleSetPrologueEnd() const + { + return handler_->HandleSetPrologueEnd(); + } + + bool HandleSetEpilogueBegin() const + { + return handler_->HandleSetEpilogueBegin(); + } + + bool HandleStartLocal() + { + auto reg_number = ReadRegisterNumber(); + auto name_index = state_->ReadULeb128(); + auto type_index = state_->ReadULeb128(); + return handler_->HandleStartLocal(reg_number, name_index, type_index); + } + + bool HandleStartLocalExtended() + { + auto reg_number = ReadRegisterNumber(); + auto name_index = state_->ReadULeb128(); + auto type_index = state_->ReadULeb128(); + auto type_signature_index = state_->ReadULeb128(); + return handler_->HandleStartLocalExtended(reg_number, name_index, type_index, type_signature_index); + } + + bool HandleEndLocal() + { + auto reg_number = ReadRegisterNumber(); + return handler_->HandleEndLocal(reg_number); + } + + bool HandleSetColumn() + { + auto cn = state_->ReadULeb128(); + return handler_->HandleSetColumn(cn); + } + + bool HandleSpecialOpcode(LineNumberProgramItem::Opcode opcode) + { + ASSERT(static_cast(opcode) >= LineNumberProgramItem::OPCODE_BASE); + + auto adjust_opcode = static_cast(opcode) - LineNumberProgramItem::OPCODE_BASE; + uint32_t pc_offset = adjust_opcode / LineNumberProgramItem::LINE_RANGE; + int32_t line_offset = adjust_opcode % LineNumberProgramItem::LINE_RANGE + LineNumberProgramItem::LINE_BASE; + return handler_->HandleSpecialOpcode(pc_offset, line_offset); + } + + LineProgramState *state_; + const uint8_t *program_; + Handler *handler_; +}; + +} // namespace panda::panda_file + +#endif // LIBPANDAFILE_LINE_NUMBER_PROGRAM_H diff --git a/libziparchive/CMakeLists.txt b/libziparchive/CMakeLists.txt index 6e590cf..163204a 100644 --- a/libziparchive/CMakeLists.txt +++ b/libziparchive/CMakeLists.txt @@ -16,8 +16,12 @@ cmake_minimum_required(VERSION 3.10) project(arkziparchive) add_library(arkziparchive ${PANDA_DEFAULT_LIB_TYPE} zip_archive.cpp) -target_include_directories(arkziparchive PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(arkziparchive arkbase miniz) +target_include_directories(arkziparchive + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC ${ZLIB_ROOT} + PUBLIC ${ZLIB_ROOT}/contrib/minizip +) +target_link_libraries(arkziparchive arkbase zlib) panda_add_gtest( NAME arkziparchive_tests @@ -28,7 +32,7 @@ panda_add_gtest( arkfile arkziparchive arkassembler - miniz + zlib SANITIZERS ${PANDA_SANITIZERS_LIST} ) @@ -38,7 +42,7 @@ panda_add_sanitizers(TARGET arkziparchive SANITIZERS ${PANDA_SANITIZERS_LIST}) if (PANDA_ENABLE_AFL) include("${PANDA_ROOT}/fuzzing/Fuzzing.cmake") - panda_substitute_libs(TARGET arkziparchive LIBS arkbase miniz) + panda_substitute_libs(TARGET arkziparchive LIBS arkbase zlib) endif() add_check_style(".") diff --git a/runtime/method.cpp b/runtime/method.cpp index 150d4da..f33d054 100644 --- a/runtime/method.cpp +++ b/runtime/method.cpp @@ -42,7 +42,7 @@ #include "libpandafile/code_data_accessor-inl.h" #include "libpandafile/debug_data_accessor-inl.h" #include "libpandafile/file-inl.h" -#include "libpandafile/line_program_state.h" +#include "libpandafile/line_number_program.h" #include "libpandafile/method_data_accessor-inl.h" #include "libpandafile/method_data_accessor.h" #include "libpandafile/proto_data_accessor-inl.h" @@ -376,6 +376,113 @@ panda_file::Type Method::GetEffectiveReturnType() const return panda_file::GetEffectiveType(GetReturnType()); } +class BytecodeOffsetResolver { +public: + BytecodeOffsetResolver(panda_file::LineProgramState *state, uint32_t bc_offset) + : state_(state), bc_offset_(bc_offset), prev_line_(state->GetLine()), line_(0) + { + } + + panda_file::LineProgramState *GetState() const + { + return state_; + } + + uint32_t GetLine() const + { + return line_; + } + + void ProcessBegin() const {} + + void ProcessEnd() + { + if (line_ == 0) { + line_ = state_->GetLine(); + } + } + + bool HandleAdvanceLine(int32_t line_diff) const + { + state_->AdvanceLine(line_diff); + return true; + } + + bool HandleAdvancePc(uint32_t pc_diff) const + { + state_->AdvancePc(pc_diff); + return true; + } + + bool HandleSetFile([[maybe_unused]] uint32_t source_file_id) const + { + return true; + } + + bool HandleSetSourceCode([[maybe_unused]] uint32_t source_code_id) const + { + return true; + } + + bool HandleSetPrologueEnd() const + { + return true; + } + + bool HandleSetEpilogueBegin() const + { + return true; + } + + bool HandleStartLocal([[maybe_unused]] int32_t reg_number, [[maybe_unused]] uint32_t name_id, + [[maybe_unused]] uint32_t type_id) const + { + return true; + } + + bool HandleStartLocalExtended([[maybe_unused]] int32_t reg_number, [[maybe_unused]] uint32_t name_id, + [[maybe_unused]] uint32_t type_id, [[maybe_unused]] uint32_t type_signature_id) const + { + return true; + } + + bool HandleEndLocal([[maybe_unused]] int32_t reg_number) const + { + return true; + } + + bool HandleSetColumn([[maybe_unused]] int32_t column_number) const + { + return true; + } + + bool HandleSpecialOpcode(uint32_t pc_offset, int32_t line_offset) + { + state_->AdvancePc(pc_offset); + state_->AdvanceLine(line_offset); + + if (state_->GetAddress() == bc_offset_) { + line_ = state_->GetLine(); + return false; + } + + if (state_->GetAddress() > bc_offset_) { + line_ = prev_line_; + return false; + } + + prev_line_ = state_->GetLine(); + + return true; + } + +private: + panda_file::LineProgramState *state_; + uint32_t bc_offset_; + uint32_t prev_line_; + uint32_t line_; +}; + int32_t Method::GetLineNumFromBytecodeOffset(uint32_t bc_offset) const { panda_file::MethodDataAccessor mda(*panda_file_, file_id_); @@ -384,65 +491,17 @@ int32_t Method::GetLineNumFromBytecodeOffset(uint32_t bc_offset) const return -1; } - using Opcode = panda_file::LineNumberProgramItem::Opcode; - using EntityId = panda_file::File::EntityId; - panda_file::DebugInfoDataAccessor dda(*panda_file_, debug_info_id.value()); const uint8_t *program = dda.GetLineNumberProgram(); - auto size = panda_file_->GetSpanFromId(panda_file_->GetIdFromPointer(program)).size(); - auto opcode_sp = Span(reinterpret_cast(program), size); - panda_file::LineProgramState state(*panda_file_, EntityId(0), dda.GetLineStart(), dda.GetConstantPool()); + panda_file::LineProgramState state(*panda_file_, panda_file::File::EntityId(0), dda.GetLineStart(), + dda.GetConstantPool()); - size_t i = 0; - Opcode opcode; - size_t prev_line = state.GetLine(); - while ((opcode = opcode_sp[i++]) != Opcode::END_SEQUENCE) { - switch (opcode) { - case Opcode::ADVANCE_LINE: { - auto line_diff = state.ReadSLeb128(); - state.AdvanceLine(line_diff); - break; - } - case Opcode::ADVANCE_PC: { - auto pc_diff = state.ReadULeb128(); - state.AdvancePc(pc_diff); - break; - } - default: { - // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_REDUNDANT_INIT) - auto opcode_value = static_cast(opcode); - if (opcode_value < panda_file::LineNumberProgramItem::OPCODE_BASE) { - break; - } + BytecodeOffsetResolver resolver(&state, bc_offset); + panda_file::LineNumberProgramProcessor program_processor(program, &resolver); + program_processor.Process(); - // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_REDUNDANT_INIT) - auto adjust_opcode = opcode_value - panda_file::LineNumberProgramItem::OPCODE_BASE; - // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_REDUNDANT_INIT) - uint32_t pc_diff = adjust_opcode / panda_file::LineNumberProgramItem::LINE_RANGE; - // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_REDUNDANT_INIT) - int32_t line_diff = adjust_opcode % panda_file::LineNumberProgramItem::LINE_RANGE + - panda_file::LineNumberProgramItem::LINE_BASE; - - state.AdvancePc(pc_diff); - state.AdvanceLine(line_diff); - - if (state.GetAddress() == bc_offset) { - return state.GetLine(); - } - - if (state.GetAddress() > bc_offset) { - return prev_line; - } - - prev_line = state.GetLine(); - - break; - } - } - } - - return state.GetLine(); + return resolver.GetLine(); } panda_file::File::StringData Method::GetClassSourceFile() const diff --git a/runtime/tests/method_test.cpp b/runtime/tests/method_test.cpp index fc2f37c..b2d2dcf 100644 --- a/runtime/tests/method_test.cpp +++ b/runtime/tests/method_test.cpp @@ -344,6 +344,66 @@ TEST_F(MethodTest, GetLineNumFromBytecodeOffset9) VerifyLineNumber({3, 4, 5, 6, 6, 7, 9, 10, 16, 12, 13, 14, 15, 11}); } +TEST_F(MethodTest, GetLineNumFromBytecodeOffset10) +{ + pandasm::Parser p; + + auto source = R"( # line 1 + .function void foo() { # line 2 + mov v0, v1 # line 3, offset 0, size 2 + mov v100, v200 # line 4, offset 2, size 3 + movi v0, 4 # line 5, offset 5, size 2 + movi v0, 100 # line 6, offset 7, size 3 + movi v0, 300 # line 7, offset 10, size 4 + return.void # line 8, offset 14, size 1 + } + )"; + + auto res = p.Parse(source); + auto &prog = res.Value(); + + auto &function = prog.function_table.at("foo"); + + pandasm::debuginfo::LocalVariable lv; + lv.name = "a"; + lv.signature = "I"; + lv.reg = 0; + lv.start = 0; + lv.length = 5; + + function.local_variable_debug.push_back(lv); + + lv.name = "b"; + lv.start = 5; + lv.length = 10; + + function.local_variable_debug.push_back(lv); + + auto pf = pandasm::AsmEmitter::Emit(res.Value()); + ASSERT_NE(pf, nullptr); + + ClassLinker *class_linker = Runtime::GetCurrent()->GetClassLinker(); + class_linker->AddPandaFile(std::move(pf)); + auto *extension = class_linker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY); + + PandaString descriptor; + + Class *klass = extension->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("_GLOBAL"), &descriptor)); + ASSERT_NE(klass, nullptr); + + Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("foo")); + ASSERT_NE(method, nullptr); + + ASSERT_EQ(method->GetLineNumFromBytecodeOffset(0), 3); + ASSERT_EQ(method->GetLineNumFromBytecodeOffset(2), 4); + ASSERT_EQ(method->GetLineNumFromBytecodeOffset(5), 5); + ASSERT_EQ(method->GetLineNumFromBytecodeOffset(7), 6); + ASSERT_EQ(method->GetLineNumFromBytecodeOffset(10), 7); + ASSERT_EQ(method->GetLineNumFromBytecodeOffset(14), 8); + + ASSERT_EQ(method->GetLineNumFromBytecodeOffset(20), 8); +} + TEST_F(MethodTest, GetClassSourceFile) { pandasm::Parser p; diff --git a/scripts/install-third-party b/scripts/install-third-party index 5ab906b..5c21863 100755 --- a/scripts/install-third-party +++ b/scripts/install-third-party @@ -51,10 +51,10 @@ echo "$MSG_PREFIX Cloning googletest from $GOOGLETEST_URL" git clone --depth=1 --verbose "$GOOGLETEST_URL" "$PANDA_THIRD_PARTY_DIR/googletest" -MINIZ_URL="https://gitee.com/openharmony/third_party_miniz.git" -echo "$MSG_PREFIX Cloning miniz from $MINIZ_URL" +ZLIB_URL="https://gitee.com/openharmony/third_party_zlib.git" +echo "$MSG_PREFIX Cloning zlib from $ZLIB_URL" -git clone --depth=1 --verbose "$MINIZ_URL" "$PANDA_THIRD_PARTY_DIR/miniz" +git clone --depth=1 --verbose "$ZLIB_URL" "$PANDA_THIRD_PARTY_DIR/zlib" echo "$MSG_PREFIX Third-party dependencies cloned" exit 0