Fix Method::GetLineNumFromBytecodeOffset

Change-Id: I82a68723ef70c57ffc7dc015333860b242d0b57f
Signed-off-by: Konstantin Baladurin <konstantin.baladurin@huawei.com>
This commit is contained in:
Konstantin Baladurin 2021-09-30 01:46:48 +03:00
parent 031d76da4d
commit 68856e746b
10 changed files with 797 additions and 275 deletions

View File

@ -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)

View File

@ -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()

View File

@ -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()

View File

@ -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<Opcode>(*program_);
++program_; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
return opcode;
}
int32_t ReadRegisterNumber()
{
auto [regiser_number, n, is_full] = leb128::DecodeSigned<int32_t>(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<uint8_t>(opcode) >= LineNumberProgramItem::OPCODE_BASE);
auto adjust_opcode = static_cast<uint8_t>(static_cast<uint8_t>(opcode) - LineNumberProgramItem::OPCODE_BASE);
auto pc_offset = static_cast<uint32_t>(adjust_opcode / LineNumberProgramItem::LINE_RANGE);
int32_t line_offset =
static_cast<int32_t>(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<LineNumberProgramHandler> 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()});
});
}
}

View File

@ -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
};

View File

@ -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<const uint8_t> 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<const uint8_t> constant_pool_;
uint32_t address_ {0};
};
template <class Handler>
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<Opcode>(*program_);
++program_; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
return opcode;
}
int32_t ReadRegisterNumber()
{
auto [regiser_number, n, is_full] = leb128::DecodeSigned<int32_t>(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<uint8_t>(opcode) >= LineNumberProgramItem::OPCODE_BASE);
auto adjust_opcode = static_cast<uint8_t>(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

View File

@ -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(".")

View File

@ -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<const Opcode *>(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<uint8_t>(opcode);
if (opcode_value < panda_file::LineNumberProgramItem::OPCODE_BASE) {
break;
}
BytecodeOffsetResolver resolver(&state, bc_offset);
panda_file::LineNumberProgramProcessor<BytecodeOffsetResolver> 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

View File

@ -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;

View File

@ -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