├── README.rst ├── VERSION ├── .gitignore ├── .style.yapf ├── config.h.in ├── src ├── pac_varfield.cc ├── pac_decl-inl.h ├── pac_utils.h ├── pac_nullptr.h ├── pac_redef.h ├── pac_type.def ├── pac_number.h ├── pac_dbg.h ├── pac_inputbuf.h ├── pac_ctype.cc ├── pac_ctype.h ├── pac_cstr.h ├── pac_externtype.def ├── pac_state.h ├── pac_enum.h ├── pac_primitive.cc ├── pac_state.cc ├── pac_utils.cc ├── pac_output.h ├── pac_regex.h ├── pac_embedded.h ├── pac_withinput.h ├── pac_conn.h ├── pac_dataptr.h ├── pac_let.h ├── pac_attr.cc ├── pac_inputbuf.cc ├── pac_varfield.h ├── pac_param.h ├── pac_expr.def ├── pac_attr.h ├── pac_btype.h ├── pac_param.cc ├── pac_flow.h ├── pac_typedecl.h ├── pac_dataunit.h ├── pac_output.cc ├── pac_dataunit.cc ├── pac_primitive.h ├── pac_exttype.h ├── pac_enum.cc ├── pac_func.h ├── pac_cclass.h ├── pac_datadep.h ├── pac_dataptr.cc ├── pac_action.h ├── pac_datadep.cc ├── pac_paramtype.h ├── pac_embedded.cc ├── pac_withinput.cc ├── pac_regex.cc ├── pac_field.h ├── pac_exttype.cc ├── pac_exception.cc ├── pac_decl.h ├── pac_exception.h ├── pac_strtype.h ├── pac_func.cc ├── pac_action.cc ├── pac_array.h ├── pac_context.h ├── pac_case.h ├── pac_context.cc ├── CMakeLists.txt ├── pac_cstr.cc ├── pac_btype.cc ├── pac_let.cc ├── pac_field.cc ├── pac_redef.cc ├── pac_conn.cc ├── pac_common.h ├── pac_decl.cc ├── pac_expr.h ├── pac_analyzer.h ├── pac_record.h └── pac_id.h ├── patches ├── README ├── binpac-7.patch ├── binpac-5.patch └── binpac-patch-doc.txt ├── lib ├── README ├── binpac_regex.cc ├── binpac_bytestring.cc ├── binpac_analyzer.h ├── CMakeLists.txt ├── binpac_regex.h ├── binpac_exception.h ├── binpac_bytestring.h ├── binpac.h.in └── binpac_buffer.h ├── .update-changes.cfg ├── .clang-tidy ├── .gitmodules ├── .git-blame-ignore-revs ├── ci ├── macos │ └── prepare.sh ├── freebsd │ └── prepare.sh ├── alpine │ └── Dockerfile ├── fedora-41 │ └── Dockerfile ├── fedora-42 │ └── Dockerfile ├── opensuse-tumbleweed │ └── Dockerfile ├── common.sh ├── debian-11 │ └── Dockerfile ├── debian-12 │ └── Dockerfile ├── ubuntu-22.04 │ └── Dockerfile ├── ubuntu-24.04 │ └── Dockerfile ├── ubuntu-24.10 │ └── Dockerfile ├── opensuse-leap-15.6 │ └── Dockerfile ├── build.sh ├── README └── centos-stream-9 │ └── Dockerfile ├── .github └── workflows │ ├── pre-commit.yml │ └── ci-notification.yml ├── .pre-commit-config.yaml ├── TODO ├── COPYING ├── Makefile ├── .cmake-format.json ├── CMakeLists.txt ├── configure └── .clang-format /README.rst: -------------------------------------------------------------------------------- 1 | README -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.61.0-67 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | 3 | # clangd 4 | .cache -------------------------------------------------------------------------------- /.style.yapf: -------------------------------------------------------------------------------- 1 | [style] 2 | column_limit=100 3 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* Version number of package */ 2 | #define BINPAC_VERSION "@BINPAC_VERSION@" 3 | -------------------------------------------------------------------------------- /src/pac_varfield.cc: -------------------------------------------------------------------------------- 1 | #include "pac_varfield.h" 2 | 3 | void PrivVarField::Prepare(Env* env) { Field::Prepare(env); } 4 | -------------------------------------------------------------------------------- /patches/README: -------------------------------------------------------------------------------- 1 | Note: It's unclear which of these patches have in fact already been 2 | applied. We should figure that out ... 3 | -------------------------------------------------------------------------------- /src/pac_decl-inl.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_decl_inl_h 2 | #define pac_decl_inl_h 3 | 4 | #include "pac_id.h" 5 | 6 | #endif // pac_decl_inl_h 7 | -------------------------------------------------------------------------------- /lib/README: -------------------------------------------------------------------------------- 1 | This directory contains a library needed by generated C++ code from 2 | binpac. Note that the library is not needed by the binpac compiler 3 | itself. 4 | -------------------------------------------------------------------------------- /.update-changes.cfg: -------------------------------------------------------------------------------- 1 | 2 | # Automatically adapt version in files. 3 | 4 | function new_version_hook 5 | { 6 | version=$1 7 | replace_version_in_rst README $version 8 | } 9 | -------------------------------------------------------------------------------- /.clang-tidy: -------------------------------------------------------------------------------- 1 | Checks: '-*, 2 | bugprone-*, 3 | modernize-use-nullptr, 4 | -bugprone-easily-swappable-parameters, 5 | clang-analyzer-*, 6 | performance-*' 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "cmake"] 2 | path = cmake 3 | url = https://github.com/zeek/cmake 4 | [submodule "auxil/libunistd"] 5 | path = auxil/libunistd 6 | url = https://github.com/zeek/libunistd 7 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # Reformat C++ code in Spicy style 2 | 784f552ffc9eabfb14b8429ae892ff8ff8068cab 3 | 4 | # Add cmake-format and typos pre-commit configs 5 | 047d69658c3ddb3bd369f9ee499432f9ee158eb4 6 | -------------------------------------------------------------------------------- /lib/binpac_regex.cc: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | namespace zeek { 5 | class RE_Matcher; 6 | } 7 | 8 | namespace binpac { 9 | 10 | std::vector* uncompiled_re_matchers = nullptr; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /ci/macos/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Preparing macOS environment" 4 | sysctl hw.model hw.machine hw.ncpu hw.physicalcpu hw.logicalcpu 5 | set -e 6 | set -x 7 | 8 | brew update 9 | brew upgrade cmake 10 | brew install bison flex 11 | -------------------------------------------------------------------------------- /ci/freebsd/prepare.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Preparing FreeBSD environment" 4 | sysctl hw.model hw.machine hw.ncpu 5 | set -e 6 | set -x 7 | 8 | env ASSUME_ALWAYS_YES=YES pkg bootstrap 9 | pkg install -y bash git cmake bison base64 flex 10 | pkg upgrade -y curl 11 | -------------------------------------------------------------------------------- /src/pac_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_utils_h 2 | #define pac_utils_h 3 | 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | char* copy_string(const char* s); 9 | string strfmt(const char* fmt, ...); 10 | char* nfmt(const char* fmt, ...); 11 | 12 | #endif /* pac_utils_h */ 13 | -------------------------------------------------------------------------------- /src/pac_nullptr.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_nullptr_h 2 | #define pac_nullptr_h 3 | 4 | #include "pac_common.h" 5 | 6 | class Nullptr : public Object { 7 | public: 8 | const char* Str() const { return s.c_str(); } 9 | 10 | protected: 11 | const string s = "nullptr"; 12 | }; 13 | 14 | #endif // pac_nullptr_h 15 | -------------------------------------------------------------------------------- /.github/workflows/pre-commit.yml: -------------------------------------------------------------------------------- 1 | name: pre-commit 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [master] 7 | 8 | jobs: 9 | pre-commit: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v3.1.0 13 | - uses: actions/setup-python@v4 14 | - uses: pre-commit/action@v3.0.0 15 | -------------------------------------------------------------------------------- /ci/alpine/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | 3 | # A version field to invalidate Cirrus's build cache when needed, as suggested in 4 | # https://github.com/cirruslabs/cirrus-ci-docs/issues/544#issuecomment-566066822 5 | ENV DOCKERFILE_VERSION 20230113 6 | 7 | RUN apk add --no-cache \ 8 | bash \ 9 | bison \ 10 | cmake \ 11 | flex-dev \ 12 | g++ \ 13 | git \ 14 | linux-headers \ 15 | make 16 | -------------------------------------------------------------------------------- /ci/fedora-41/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:41 2 | 3 | # A version field to invalidate Cirrus's build cache when needed, as suggested in 4 | # https://github.com/cirruslabs/cirrus-ci-docs/issues/544#issuecomment-566066822 5 | ENV DOCKERFILE_VERSION 20241204 6 | 7 | RUN dnf -y install \ 8 | bison \ 9 | cmake \ 10 | flex \ 11 | gcc \ 12 | gcc-c++ \ 13 | git \ 14 | make \ 15 | && dnf clean all && rm -rf /var/cache/dnf 16 | -------------------------------------------------------------------------------- /src/pac_redef.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_redef_h 2 | #define pac_redef_h 3 | 4 | #include "pac_decl.h" 5 | 6 | Decl* ProcessCaseTypeRedef(const ID* id, CaseFieldList* casefieldlist); 7 | Decl* ProcessCaseExprRedef(const ID* id, CaseExprList* caseexprlist); 8 | Decl* ProcessAnalyzerRedef(const ID* id, Decl::DeclType decl_type, AnalyzerElementList* elements); 9 | Decl* ProcessTypeAttrRedef(const ID* id, AttrList* attrlist); 10 | 11 | #endif // pac_redef_h 12 | -------------------------------------------------------------------------------- /src/pac_type.def: -------------------------------------------------------------------------------- 1 | // TYPEDEF(type_id, pac_type, c_type, size) 2 | TYPE_DEF(INT8, "int8", "int8", 1) 3 | TYPE_DEF(INT16, "int16", "int16", 2) 4 | TYPE_DEF(INT32, "int32", "int32", 4) 5 | TYPE_DEF(INT64, "int64", "int64", 8) 6 | TYPE_DEF(UINT8, "uint8", "uint8", 1) 7 | TYPE_DEF(UINT16, "uint16", "uint16", 2) 8 | TYPE_DEF(UINT32, "uint32", "uint32", 4) 9 | TYPE_DEF(UINT64, "uint64", "uint64", 8) 10 | TYPE_DEF(EMPTY, "empty", "", 0) 11 | -------------------------------------------------------------------------------- /ci/fedora-42/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM fedora:42 2 | 3 | # A version field to invalidate Cirrus's build cache when needed, as suggested in 4 | # https://github.com/cirruslabs/cirrus-ci-docs/issues/544#issuecomment-566066822 5 | ENV DOCKERFILE_VERSION 20250508 6 | 7 | RUN dnf -y install \ 8 | bison \ 9 | cmake \ 10 | flex \ 11 | gawk \ 12 | gcc \ 13 | gcc-c++ \ 14 | git \ 15 | make \ 16 | && dnf clean all && rm -rf /var/cache/dnf 17 | -------------------------------------------------------------------------------- /ci/opensuse-tumbleweed/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM opensuse/tumbleweed 2 | 3 | # A version field to invalidate Cirrus's build cache when needed, as suggested in 4 | # https://github.com/cirruslabs/cirrus-ci-docs/issues/544#issuecomment-566066822 5 | ENV DOCKERFILE_VERSION 20221027 6 | 7 | RUN zypper refresh \ 8 | && zypper in -y \ 9 | bison \ 10 | cmake \ 11 | flex \ 12 | gcc \ 13 | gcc-c++ \ 14 | git \ 15 | make \ 16 | && rm -rf /var/cache/zypp 17 | -------------------------------------------------------------------------------- /src/pac_number.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_number_h 2 | #define pac_number_h 3 | 4 | #include "pac_common.h" 5 | 6 | class Number : public Object { 7 | public: 8 | Number(int arg_n) : s(strfmt("%d", arg_n)), n(arg_n) {} 9 | Number(const char* arg_s, int arg_n) : s(arg_s), n(arg_n) {} 10 | const char* Str() const { return s.c_str(); } 11 | int Num() const { return n; } 12 | 13 | protected: 14 | const string s; 15 | const int n; 16 | }; 17 | 18 | #endif // pac_number_h 19 | -------------------------------------------------------------------------------- /ci/common.sh: -------------------------------------------------------------------------------- 1 | # Common material sourced by Bash CI scripts in this directory 2 | 3 | # On Cirrus, oversubscribe the CPUs when on Linux or FreeBSD. This uses Cirrus' "greedy" feature. 4 | if [[ "${CIRRUS_OS}" == linux || "${CIRRUS_OS}" == freebsd ]]; then 5 | if [[ -n "${ZEEK_CI_CPUS}" ]]; then 6 | ZEEK_CI_CPUS=$((2 * ${ZEEK_CI_CPUS})) 7 | fi 8 | 9 | if [[ -n "${ZEEK_CI_BTEST_JOBS}" ]]; then 10 | ZEEK_CI_BTEST_JOBS=$((2 * ${ZEEK_CI_BTEST_JOBS})) 11 | fi 12 | fi 13 | -------------------------------------------------------------------------------- /lib/binpac_bytestring.cc: -------------------------------------------------------------------------------- 1 | #define binpac_regex_h 2 | 3 | #include "binpac_bytestring.h" 4 | 5 | #include 6 | 7 | namespace binpac { 8 | 9 | std::string std_string(bytestring const* s) { return std::string((const char*)s->begin(), (const char*)s->end()); } 10 | 11 | int bytestring_to_int(bytestring const* s) { return atoi((const char*)s->begin()); } 12 | 13 | double bytestring_to_double(bytestring const* s) { return atof((const char*)s->begin()); } 14 | 15 | } // namespace binpac 16 | -------------------------------------------------------------------------------- /src/pac_dbg.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_dbg_h 2 | #define pac_dbg_h 3 | 4 | #include 5 | #include 6 | 7 | extern bool FLAGS_pac_debug; 8 | 9 | #define ASSERT(x) assert(x) 10 | #define DEBUG_MSG(...) \ 11 | if ( FLAGS_pac_debug ) \ 12 | fprintf(stderr, __VA_ARGS__) 13 | 14 | #endif /* pac_dbg_h */ 15 | -------------------------------------------------------------------------------- /ci/debian-11/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:11 2 | 3 | ENV DEBIAN_FRONTEND="noninteractive" TZ="America/Los_Angeles" 4 | 5 | # A version field to invalidate Cirrus's build cache when needed, as suggested in 6 | # https://github.com/cirruslabs/cirrus-ci-docs/issues/544#issuecomment-566066822 7 | ENV DOCKERFILE_VERSION 20220519 8 | 9 | RUN apt-get update && apt-get -y install \ 10 | bison \ 11 | cmake \ 12 | flex \ 13 | g++ \ 14 | gcc \ 15 | git \ 16 | make \ 17 | && apt autoclean \ 18 | && rm -rf /var/lib/apt/lists/* 19 | -------------------------------------------------------------------------------- /ci/debian-12/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:12 2 | 3 | ENV DEBIAN_FRONTEND="noninteractive" TZ="America/Los_Angeles" 4 | 5 | # A version field to invalidate Cirrus's build cache when needed, as suggested in 6 | # https://github.com/cirruslabs/cirrus-ci-docs/issues/544#issuecomment-566066822 7 | ENV DOCKERFILE_VERSION 20231213 8 | 9 | RUN apt-get update && apt-get -y install \ 10 | bison \ 11 | cmake \ 12 | flex \ 13 | g++ \ 14 | gcc \ 15 | git \ 16 | make \ 17 | && apt autoclean \ 18 | && rm -rf /var/lib/apt/lists/* 19 | -------------------------------------------------------------------------------- /src/pac_inputbuf.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_inputbuf_h 2 | #define pac_inputbuf_h 3 | 4 | #include "pac_datadep.h" 5 | #include "pac_dataptr.h" 6 | 7 | class Expr; 8 | 9 | class InputBuffer : public Object, public DataDepElement { 10 | public: 11 | InputBuffer(Expr* expr); 12 | 13 | bool RequiresAnalyzerContext() const; 14 | DataPtr GenDataBeginEnd(Output* out_cc, Env* env); 15 | 16 | protected: 17 | bool DoTraverse(DataDepVisitor* visitor) override; 18 | 19 | private: 20 | Expr* expr_; 21 | }; 22 | 23 | #endif // pac_inputbuf_h 24 | -------------------------------------------------------------------------------- /ci/ubuntu-22.04/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:22.04 2 | 3 | ENV DEBIAN_FRONTEND="noninteractive" TZ="America/Los_Angeles" 4 | 5 | # A version field to invalidate Cirrus's build cache when needed, as suggested in 6 | # https://github.com/cirruslabs/cirrus-ci-docs/issues/544#issuecomment-566066822 7 | ENV DOCKERFILE_VERSION 20220614 8 | 9 | RUN apt-get update && apt-get -y install \ 10 | bison \ 11 | cmake \ 12 | flex \ 13 | g++ \ 14 | gcc \ 15 | git \ 16 | make \ 17 | && apt autoclean \ 18 | && rm -rf /var/lib/apt/lists/* 19 | -------------------------------------------------------------------------------- /ci/ubuntu-24.04/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | 3 | ENV DEBIAN_FRONTEND="noninteractive" TZ="America/Los_Angeles" 4 | 5 | # A version field to invalidate Cirrus's build cache when needed, as suggested in 6 | # https://github.com/cirruslabs/cirrus-ci-docs/issues/544#issuecomment-566066822 7 | ENV DOCKERFILE_VERSION 20240510 8 | 9 | RUN apt-get update && apt-get -y install \ 10 | bison \ 11 | cmake \ 12 | flex \ 13 | g++ \ 14 | gcc \ 15 | git \ 16 | make \ 17 | && apt autoclean \ 18 | && rm -rf /var/lib/apt/lists/* 19 | -------------------------------------------------------------------------------- /ci/ubuntu-24.10/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.10 2 | 3 | ENV DEBIAN_FRONTEND="noninteractive" TZ="America/Los_Angeles" 4 | 5 | # A version field to invalidate Cirrus's build cache when needed, as suggested in 6 | # https://github.com/cirruslabs/cirrus-ci-docs/issues/544#issuecomment-566066822 7 | ENV DOCKERFILE_VERSION 20241204 8 | 9 | RUN apt-get update && apt-get -y install \ 10 | bison \ 11 | cmake \ 12 | flex \ 13 | g++ \ 14 | gcc \ 15 | git \ 16 | make \ 17 | && apt autoclean \ 18 | && rm -rf /var/lib/apt/lists/* 19 | -------------------------------------------------------------------------------- /src/pac_ctype.cc: -------------------------------------------------------------------------------- 1 | #include "pac_ctype.h" 2 | 3 | string CType::DeclareInstance(const string& var) const { return strfmt("%s %s", name().c_str(), var.c_str()); } 4 | 5 | string CType::DeclareConstReference(const string& var) const { 6 | return strfmt("%s const& %s", name().c_str(), var.c_str()); 7 | } 8 | 9 | string CType::DeclareConstPointer(const string& var) const { 10 | return strfmt("%s const* %s", name().c_str(), var.c_str()); 11 | } 12 | 13 | string CType::DeclarePointer(const string& var) const { return strfmt("%s* %s", name().c_str(), var.c_str()); } 14 | -------------------------------------------------------------------------------- /src/pac_ctype.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_ctype_h 2 | #define pac_ctype_h 3 | 4 | #include "pac_common.h" 5 | 6 | // Represents a C++ type 7 | class CType { 8 | public: 9 | CType(const string& name); 10 | 11 | string name() const { return name_; } 12 | 13 | string DeclareInstance(const string& var) const; 14 | string DeclareConstReference(const string& var) const; 15 | string DeclareConstPointer(const string& var) const; 16 | string DeclarePointer(const string& var) const; 17 | 18 | protected: 19 | string name_; 20 | }; 21 | 22 | #endif // pac_ctype_h 23 | -------------------------------------------------------------------------------- /src/pac_cstr.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_cstr_h 2 | #define pac_cstr_h 3 | 4 | #include "pac_common.h" 5 | 6 | class ConstString : public Object { 7 | public: 8 | ConstString(const string& s); 9 | 10 | // The string in its escaped form, with surrounding '"'s 11 | const string& str() const { return str_; } 12 | const char* c_str() const { return str_.c_str(); } 13 | 14 | // The unescaped string, without surrounding '"'s 15 | const string& unescaped() const { return unescaped_; } 16 | 17 | private: 18 | string str_; 19 | string unescaped_; 20 | }; 21 | 22 | #endif // pac_cstr_h 23 | -------------------------------------------------------------------------------- /src/pac_externtype.def: -------------------------------------------------------------------------------- 1 | EXTERNTYPE(bool, bool, BOOLEAN) 2 | EXTERNTYPE(int, int, NUMBER) 3 | EXTERNTYPE(double, double, NUMBER) 4 | EXTERNTYPE(string, string, PLAIN) 5 | EXTERNTYPE(void, void, PLAIN) 6 | EXTERNTYPE(voidptr, void, POINTER) 7 | EXTERNTYPE(nullptr, nullptr, PLAIN) 8 | EXTERNTYPE(bytearray, bytearray, PLAIN) 9 | EXTERNTYPE(const_charptr, const_charptr, PLAIN) 10 | EXTERNTYPE(const_byteptr, const_byteptr, PLAIN) 11 | // EXTERNTYPE(const_byteseg, const_byteseg, PLAIN) 12 | EXTERNTYPE(const_bytestring, const_bytestring, PLAIN) 13 | // EXTERNTYPE(bytestring, bytestring, PLAIN) 14 | EXTERNTYPE(re_matcher, re_matcher, PLAIN) 15 | EXTERNTYPE(flowbuffer, FlowBuffer, POINTER) 16 | -------------------------------------------------------------------------------- /lib/binpac_analyzer.h: -------------------------------------------------------------------------------- 1 | #ifndef binpac_an_h 2 | #define binpac_an_h 3 | 4 | namespace binpac { 5 | 6 | // TODO: Add the Done() function 7 | 8 | // The interface for a connection analyzer 9 | class ConnectionAnalyzer { 10 | public: 11 | virtual ~ConnectionAnalyzer() = default; 12 | virtual void NewData(bool is_orig, const unsigned char* begin_of_data, const unsigned char* end_of_data) = 0; 13 | }; 14 | 15 | // The interface for a flow analyzer 16 | class FlowAnalyzer { 17 | public: 18 | virtual ~FlowAnalyzer() = default; 19 | virtual void NewData(const unsigned char* begin_of_data, const unsigned char* end_of_data) = 0; 20 | }; 21 | 22 | } // namespace binpac 23 | 24 | #endif // binpac_an_h 25 | -------------------------------------------------------------------------------- /src/pac_state.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_state_h 2 | #define pac_state_h 3 | 4 | // Classes representing analyzer states. 5 | 6 | #include "pac_common.h" 7 | 8 | class StateVar { 9 | public: 10 | StateVar(ID* id, Type* type) : id_(id), type_(type) {} 11 | 12 | const ID* id() const { return id_; } 13 | Type* type() const { return type_; } 14 | 15 | void GenDecl(Output* out_h, Env* env); 16 | void GenAccessFunction(Output* out_h, Env* env); 17 | void GenSetFunction(Output* out_h, Env* env); 18 | void GenInitCode(Output* out_cc, Env* env); 19 | void GenCleanUpCode(Output* out_cc, Env* env); 20 | 21 | private: 22 | ID* id_; 23 | Type* type_; 24 | }; 25 | 26 | #endif // pac_state_h 27 | -------------------------------------------------------------------------------- /ci/opensuse-leap-15.6/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM opensuse/leap:15.6 2 | 3 | # A version field to invalidate Cirrus's build cache when needed, as suggested in 4 | # https://github.com/cirruslabs/cirrus-ci-docs/issues/544#issuecomment-566066822 5 | ENV DOCKERFILE_VERSION 20240524 6 | 7 | RUN zypper addrepo https://download.opensuse.org/repositories/openSUSE:Leap:15.6:Update/standard/openSUSE:Leap:15.6:Update.repo \ 8 | && zypper refresh \ 9 | && zypper in -y \ 10 | bison \ 11 | cmake \ 12 | flex \ 13 | gcc10 \ 14 | gcc10-c++ \ 15 | git \ 16 | make \ 17 | && rm -rf /var/cache/zypp 18 | 19 | RUN update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-10 100 20 | RUN update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-10 100 21 | -------------------------------------------------------------------------------- /src/pac_enum.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_enum_h 2 | #define pac_enum_h 3 | 4 | #include "pac_decl.h" 5 | 6 | class Enum { 7 | public: 8 | Enum(ID* id, Expr* expr = 0); 9 | ~Enum(); 10 | 11 | void GenHeader(Output* out_h, int* pval); 12 | 13 | private: 14 | ID* id_; 15 | Expr* expr_; 16 | }; 17 | 18 | class EnumDecl : public Decl { 19 | public: 20 | EnumDecl(ID* id, EnumList* enumlist); 21 | ~EnumDecl() override; 22 | 23 | Type* DataType() const { return datatype_; } 24 | 25 | void Prepare() override; 26 | void GenForwardDeclaration(Output* out_h) override; 27 | void GenCode(Output* out_h, Output* out_cc) override; 28 | 29 | private: 30 | EnumList* enumlist_; 31 | Type* datatype_; 32 | TypeDecl* extern_typedecl_; 33 | }; 34 | 35 | #endif // pac_enum_h 36 | -------------------------------------------------------------------------------- /patches/binpac-7.patch: -------------------------------------------------------------------------------- 1 | diff -urN bro-1.2.1-orig/src/pac_type.cc bro-1.2.1-ssl-binpac/src/pac_type.cc 2 | --- bro-1.2.1-orig/src/pac_type.cc 2006-07-26 15:02:40.000000000 -0700 3 | +++ bro-1.2.1-ssl-binpac/src/pac_type.cc 2007-05-24 10:56:42.140658000 -0700 4 | @@ -393,7 +393,7 @@ 5 | break; 6 | 7 | case BUFFER_BY_LENGTH: 8 | - if ( buffering_state_var_field_ ) 9 | + if ( env->GetDataType(buffering_state_id) ) 10 | { 11 | out_cc->println("if ( %s == 0 )", 12 | env->RValue(buffering_state_id)); 13 | @@ -421,7 +421,7 @@ 14 | frame_buffer_arg.c_str(), 15 | attr_chunked() ? "true" : "false"); 16 | 17 | - if ( buffering_state_var_field_ ) 18 | + if ( env->GetDataType(buffering_state_id) ) 19 | { 20 | out_cc->println("%s = 1;", 21 | env->LValue(buffering_state_id)); 22 | -------------------------------------------------------------------------------- /src/pac_primitive.cc: -------------------------------------------------------------------------------- 1 | #include "pac_primitive.h" 2 | 3 | #include "pac_dbg.h" 4 | #include "pac_expr.h" 5 | #include "pac_id.h" 6 | #include "pac_type.h" 7 | 8 | string PPVal::ToCode(Env* env) { 9 | ASSERT(expr_); 10 | return string(expr_->EvalExpr(nullptr, env)); 11 | } 12 | 13 | string PPSet::ToCode(Env* env) { 14 | ASSERT(expr_); 15 | return expr_->SetFunc(nullptr, env); 16 | } 17 | 18 | string PPType::ToCode(Env* env) { 19 | Type* type = expr_->DataType(env); 20 | return type->DataTypeStr(); 21 | } 22 | 23 | string PPConstDef::ToCode(Env* env) { 24 | Type* type = expr_->DataType(env); 25 | env->AddID(id_, TEMP_VAR, type); 26 | env->SetEvaluated(id_); 27 | 28 | string type_str = type->DataTypeStr(); 29 | return strfmt("%s %s = %s", type_str.c_str(), env->LValue(id_), expr_->EvalExpr(nullptr, env)); 30 | } 31 | -------------------------------------------------------------------------------- /src/pac_state.cc: -------------------------------------------------------------------------------- 1 | #include "pac_state.h" 2 | 3 | #include "pac_id.h" 4 | #include "pac_output.h" 5 | #include "pac_type.h" 6 | 7 | void StateVar::GenDecl(Output* out_h, Env* env) { 8 | out_h->println("%s %s;", type_->DataTypeStr().c_str(), env->LValue(id_)); 9 | } 10 | 11 | void StateVar::GenAccessFunction(Output* out_h, Env* env) { 12 | out_h->println("%s %s const { return %s; }", type_->DataTypeConstRefStr().c_str(), env->RValue(id_), 13 | env->LValue(id_)); 14 | } 15 | 16 | void StateVar::GenSetFunction(Output* out_h, Env* env) { 17 | out_h->println("void %s(%s x) { %s = x; }", set_function(id_).c_str(), type_->DataTypeConstRefStr().c_str(), 18 | env->LValue(id_)); 19 | } 20 | 21 | void StateVar::GenInitCode(Output* out_cc, Env* env) {} 22 | 23 | void StateVar::GenCleanUpCode(Output* out_cc, Env* env) {} 24 | -------------------------------------------------------------------------------- /src/pac_utils.cc: -------------------------------------------------------------------------------- 1 | #include "pac_utils.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | char* copy_string(const char* s) { 8 | char* c = new char[strlen(s) + 1]; 9 | strcpy(c, s); 10 | return c; 11 | } 12 | 13 | namespace { 14 | 15 | const char* do_fmt(const char* format, va_list ap) { 16 | static char buf[1024]; 17 | vsnprintf(buf, sizeof(buf), format, ap); 18 | return buf; 19 | } 20 | 21 | } // namespace 22 | 23 | string strfmt(const char* format, ...) { 24 | va_list ap; 25 | va_start(ap, format); 26 | const char* r = do_fmt(format, ap); 27 | va_end(ap); 28 | return string(r); 29 | } 30 | 31 | char* nfmt(const char* format, ...) { 32 | va_list ap; 33 | va_start(ap, format); 34 | const char* r = do_fmt(format, ap); 35 | va_end(ap); 36 | return copy_string(r); 37 | } 38 | -------------------------------------------------------------------------------- /src/pac_output.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_output_h 2 | #define pac_output_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace std; 9 | 10 | class OutputException { 11 | public: 12 | OutputException(const char* arg_msg); 13 | ~OutputException(); 14 | const char* errmsg() const { return msg.c_str(); } 15 | 16 | protected: 17 | string msg; 18 | }; 19 | 20 | class Output { 21 | public: 22 | Output(string filename); 23 | ~Output(); 24 | 25 | int println(const char* fmt, ...); 26 | int print(const char* fmt, ...); 27 | 28 | int indent() const { return indent_; } 29 | 30 | void inc_indent() { ++indent_; } 31 | void dec_indent() { --indent_; } 32 | 33 | protected: 34 | int print(const char* fmt, va_list ap); 35 | 36 | FILE* fp; 37 | int indent_; 38 | }; 39 | 40 | #endif /* pac_output_h */ 41 | -------------------------------------------------------------------------------- /ci/build.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)" 4 | . ${SCRIPT_DIR}/common.sh 5 | 6 | set -e 7 | set -x 8 | 9 | if [[ "${CIRRUS_OS}" == "darwin" ]]; then 10 | # Starting with Monterey & Xcode 13.1 we need to help it find OpenSSL 11 | if [ -d /usr/local/opt/openssl@1.1/lib/pkgconfig ]; then 12 | export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/opt/openssl@1.1/lib/pkgconfig 13 | fi 14 | fi 15 | 16 | if [[ "${ZEEK_CI_CREATE_ARTIFACT}" != "1" ]]; then 17 | ./configure ${ZEEK_CI_CONFIGURE_FLAGS} 18 | cd build 19 | make -j ${ZEEK_CI_CPUS} 20 | else 21 | ./configure ${ZEEK_CI_CONFIGURE_FLAGS} --prefix=${CIRRUS_WORKING_DIR}/install 22 | cd build 23 | make -j ${ZEEK_CI_CPUS} install 24 | cd .. 25 | tar -czf ${CIRRUS_WORKING_DIR}/build.tgz ${CIRRUS_WORKING_DIR}/install 26 | fi 27 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # See https://pre-commit.com for more information 2 | # See https://pre-commit.com/hooks.html for more hooks 3 | # 4 | repos: 5 | - repo: https://github.com/pre-commit/mirrors-clang-format 6 | rev: 'v17.0.3' 7 | hooks: 8 | - id: clang-format 9 | types_or: 10 | - "c" 11 | - "c++" 12 | - "json" 13 | 14 | - repo: https://github.com/maxwinterstein/shfmt-py 15 | rev: v3.7.0.1 16 | hooks: 17 | - id: shfmt 18 | args: ["-w", "-i", "4", "-ci"] 19 | 20 | - repo: https://github.com/cheshirekow/cmake-format-precommit 21 | rev: v0.6.13 22 | hooks: 23 | - id: cmake-format 24 | exclude: '^auxil/.*$' 25 | 26 | - repo: https://github.com/crate-ci/typos 27 | rev: v1.16.21 28 | hooks: 29 | - id: typos 30 | exclude: '^(.typos.toml|src/SmithWaterman.cc|testing/.*|auxil/.*|scripts/base/frameworks/files/magic/.*|CHANGES)$' 31 | -------------------------------------------------------------------------------- /src/pac_regex.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_regex_h 2 | #define pac_regex_h 3 | 4 | #include "pac_common.h" 5 | #include "pac_decl.h" 6 | 7 | class RegExDecl; 8 | 9 | class RegEx : public Object { 10 | public: 11 | RegEx(const string& str); 12 | ~RegEx(); 13 | 14 | const string& str() const { return str_; } 15 | ID* matcher_id() const { return matcher_id_; } 16 | 17 | private: 18 | string str_; 19 | ID* matcher_id_; 20 | RegExDecl* decl_; 21 | 22 | public: 23 | static const char* kREMatcherType; 24 | static const char* kMatchPrefix; 25 | }; 26 | 27 | class RegExDecl : public Decl { 28 | public: 29 | RegExDecl(RegEx* regex); 30 | 31 | void Prepare() override; 32 | void GenForwardDeclaration(Output* out_h) override; 33 | void GenCode(Output* out_h, Output* out_cc) override; 34 | 35 | private: 36 | RegEx* regex_; 37 | }; 38 | 39 | #endif // pac_regex_h 40 | -------------------------------------------------------------------------------- /ci/README: -------------------------------------------------------------------------------- 1 | ========================================= 2 | Continuous Integration Configuration Info 3 | ========================================= 4 | 5 | The following pointers are aimed at maintainers to help describe a few points 6 | about the Cirrus CI setup that may not be obvious/intuitive. 7 | 8 | Email Notifications 9 | ------------------- 10 | 11 | Cirrus CI doesn't feature any way to perform email notifications on failures, 12 | so that is instead handled by a separate GitHub Action: 13 | 14 | https://github.com/zeek/ci-email-action 15 | 16 | The configuration of that GitHub Action is typical: it's the 17 | ``.github/workflows/ci-notification.yml`` file, which sets SMTP/mail info 18 | via secrets stored in GitHub for the Zeek organization: 19 | 20 | https://github.com/organizations/zeek/settings/secrets 21 | 22 | The particular values used for those are currently from the Zeek project's AWS 23 | Simple Email Service configuration. 24 | -------------------------------------------------------------------------------- /src/pac_embedded.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_embedded_h 2 | #define pac_embedded_h 3 | 4 | #include "pac_common.h" 5 | 6 | class EmbeddedCodeSegment { 7 | public: 8 | explicit EmbeddedCodeSegment(const string& s); 9 | explicit EmbeddedCodeSegment(PacPrimitive* primitive); 10 | ~EmbeddedCodeSegment(); 11 | 12 | string ToCode(Env* env); 13 | 14 | private: 15 | string s_; 16 | PacPrimitive* primitive_; 17 | }; 18 | 19 | typedef vector EmbeddedCodeSegmentList; 20 | 21 | class EmbeddedCode : public Object { 22 | public: 23 | EmbeddedCode(); 24 | ~EmbeddedCode(); 25 | 26 | // Append a character 27 | void Append(int atom); 28 | void Append(const char* str); 29 | 30 | // Append a PAC primitive 31 | void Append(PacPrimitive* primitive); 32 | 33 | void GenCode(Output* out, Env* env); 34 | 35 | private: 36 | string current_segment_; 37 | EmbeddedCodeSegmentList* segments_; 38 | }; 39 | 40 | #endif // pac_embedded_h 41 | -------------------------------------------------------------------------------- /.github/workflows/ci-notification.yml: -------------------------------------------------------------------------------- 1 | name: CI Email Notification 2 | on: 3 | check_suite: 4 | types: [completed] 5 | jobs: 6 | notify: 7 | if: github.repository == 'zeek/binpac' 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Show the event 11 | run: cat "$GITHUB_EVENT_PATH" || true 12 | 13 | - name: Send CI Email Notification 14 | uses: zeek/ci-email-action@master 15 | env: 16 | CI_APP_NAME: "Cirrus CI" 17 | BRANCH_REGEX: "master|release/.*" 18 | SKIP_CONCLUSIONS: 'cancelled,neutral,skipped' 19 | SMTP_HOST: ${{ secrets.SMTP_HOST }} 20 | SMTP_PORT: ${{ secrets.SMTP_PORT }} 21 | SMTP_USER: ${{ secrets.SMTP_USER }} 22 | SMTP_PASS: ${{ secrets.SMTP_PASS }} 23 | MAIL_FROM: ${{ secrets.MAIL_FROM }} 24 | MAIL_TO: ${{ secrets.MAIL_TO }} 25 | MAIL_REPLY_TO: ${{ secrets.MAIL_REPLY_TO }} 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | -------------------------------------------------------------------------------- /src/pac_withinput.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_withinput_h 2 | #define pac_withinput_h 3 | 4 | #include "pac_datadep.h" 5 | #include "pac_decl.h" 6 | #include "pac_field.h" 7 | 8 | class WithInputField : public Field, public Evaluatable { 9 | public: 10 | WithInputField(ID* id, Type* type, InputBuffer* input); 11 | ~WithInputField() override; 12 | 13 | InputBuffer* input() const { return input_; } 14 | 15 | void Prepare(Env* env) override; 16 | 17 | // void GenPubDecls(Output* out, Env* env); 18 | // void GenPrivDecls(Output* out, Env* env); 19 | 20 | // void GenInitCode(Output* out, Env* env); 21 | // void GenCleanUpCode(Output* out, Env* env); 22 | 23 | void GenParseCode(Output* out, Env* env); 24 | 25 | // Instantiate the Evaluatable interface 26 | void GenEval(Output* out, Env* env) override; 27 | 28 | bool RequiresAnalyzerContext() const override; 29 | 30 | protected: 31 | bool DoTraverse(DataDepVisitor* visitor) override; 32 | 33 | protected: 34 | InputBuffer* input_; 35 | }; 36 | 37 | #endif // pac_withinput_h 38 | -------------------------------------------------------------------------------- /src/pac_conn.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_conn_h 2 | #define pac_conn_h 3 | 4 | #include "pac_analyzer.h" 5 | #include "pac_decl.h" 6 | 7 | class ConnDecl : public AnalyzerDecl { 8 | public: 9 | ConnDecl(ID* conn_id, ParamList* params, AnalyzerElementList* elemlist); 10 | ~ConnDecl() override; 11 | 12 | void Prepare() override; 13 | 14 | Type* DataType() const { return data_type_; } 15 | 16 | protected: 17 | void AddBaseClass(vector* base_classes) const override; 18 | 19 | void GenProcessFunc(Output* out_h, Output* out_cc) override; 20 | void GenGapFunc(Output* out_h, Output* out_cc) override; 21 | void GenEOFFunc(Output* out_h, Output* out_cc) override; 22 | 23 | void GenPubDecls(Output* out_h, Output* out_cc) override; 24 | void GenPrivDecls(Output* out_h, Output* out_cc) override; 25 | 26 | void ProcessFlowElement(AnalyzerFlow* flow_elem) override; 27 | void ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) override; 28 | 29 | AnalyzerFlow* flows_[2]; 30 | Type* data_type_; 31 | }; 32 | 33 | #endif // pac_conn_h 34 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | Big features 2 | * Variable context (xid, call in RPC)? -- no variable context 3 | * Helpers 4 | * Connection states and actions 5 | * Case and analyzer redef 6 | * &also withinput 7 | * Explicit analyzer context (interface + instantiation) "withcontext" 8 | + Interface with C++ and Zeek (events, extern, weird) 9 | + Incremental input 10 | + ASCII protocols 11 | + Reassembly 12 | - Dealing with exceptions 13 | - Dependency analysis to save parsing time on unused fields 14 | - Performance measurement 15 | 16 | Small features 17 | * Restructure the code: break up pac.{h,cc} 18 | * ref counting (to keep certain structures) 19 | * analyzer context as a parameter of class 20 | * &autolength 21 | * find a better name for "analyzer_context" ("analcxt", "context", "analyzer") $context 22 | * &if 23 | * &autolength (now &restofdata) 24 | * Use vector<> instead of array<>? 25 | * set end_of_data when &length = ... 26 | - make the `default' case mandatory? 27 | - &inline 28 | - &warn and &check? (follow &if) 29 | - typedef? 30 | 31 | Binpac 1 32 | - create a namespace for each .pac file 33 | - type equivalence 34 | - byteorder() for every type? 35 | -------------------------------------------------------------------------------- /ci/centos-stream-9/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/centos/centos:stream9 2 | 3 | # A version field to invalidate Cirrus's build cache when needed, as suggested in 4 | # https://github.com/cirruslabs/cirrus-ci-docs/issues/544#issuecomment-566066822 5 | ENV DOCKERFILE_VERSION 20220519 6 | 7 | # dnf config-manager isn't available at first, and 8 | # we need it to install the CRB repo below. 9 | RUN dnf -y install 'dnf-command(config-manager)' 10 | 11 | # What used to be powertools is now called "CRB". 12 | # We need it for some of the packages installed below. 13 | # https://docs.fedoraproject.org/en-US/epel/ 14 | RUN dnf config-manager --set-enabled crb 15 | RUN dnf -y install \ 16 | https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm \ 17 | https://dl.fedoraproject.org/pub/epel/epel-next-release-latest-9.noarch.rpm 18 | 19 | # The --nobest flag is hopefully temporary. Without it we currently hit 20 | # package versioning conflicts around OpenSSL. 21 | RUN dnf -y --nobest install \ 22 | bison \ 23 | cmake \ 24 | flex \ 25 | gcc \ 26 | gcc-c++ \ 27 | git \ 28 | make \ 29 | && dnf clean all && rm -rf /var/cache/dnf 30 | -------------------------------------------------------------------------------- /src/pac_dataptr.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_dataptr_h 2 | #define pac_dataptr_h 3 | 4 | #include 5 | 6 | #include "pac_common.h" 7 | #include "pac_dbg.h" 8 | 9 | // A data pointer is represented by an data pointer variable 10 | // plus a constant offset. 11 | 12 | class DataPtr { 13 | public: 14 | DataPtr(Env* env, const ID* arg_id, const int arg_off); 15 | DataPtr(DataPtr const& x) { *this = x; } 16 | 17 | DataPtr const& operator=(DataPtr const& x) { 18 | id_ = x.id(); 19 | offset_ = x.offset(); 20 | ptr_expr_ = x.ptr_expr(); 21 | 22 | return *this; 23 | } 24 | 25 | const ID* id() const { return id_; } 26 | int offset() const { return offset_; } 27 | 28 | const char* ptr_expr() const { 29 | ASSERT(id_); 30 | return ptr_expr_.c_str(); 31 | } 32 | 33 | int AbsOffset(const ID* base_ptr) const; 34 | char* AbsOffsetExpr(Env* env, const ID* base_ptr) const; 35 | 36 | void GenBoundaryCheck(Output* out, Env* env, const char* data_size, const char* data_name) const; 37 | 38 | protected: 39 | const ID* id_; 40 | int offset_; 41 | string ptr_expr_; 42 | }; 43 | 44 | #endif // pac_dataptr_h 45 | -------------------------------------------------------------------------------- /src/pac_let.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_let_h 2 | #define pac_let_h 3 | 4 | #include "pac_decl.h" 5 | #include "pac_field.h" 6 | 7 | class LetField : public Field, Evaluatable { 8 | public: 9 | LetField(ID* arg_id, Type* type, Expr* arg_expr); 10 | ~LetField() override; 11 | 12 | Expr* expr() const { return expr_; } 13 | 14 | void Prepare(Env* env) override; 15 | 16 | void GenInitCode(Output* out, Env* env) override; 17 | void GenParseCode(Output* out, Env* env); 18 | void GenEval(Output* out, Env* env) override; 19 | 20 | bool RequiresAnalyzerContext() const override; 21 | 22 | protected: 23 | bool DoTraverse(DataDepVisitor* visitor) override; 24 | 25 | protected: 26 | Expr* expr_; 27 | }; 28 | 29 | class LetDecl : public Decl, Evaluatable { 30 | public: 31 | LetDecl(ID* id, Type* type, Expr* expr); 32 | ~LetDecl() override; 33 | 34 | Expr* expr() const { return expr_; } 35 | 36 | void Prepare() override; 37 | void GenForwardDeclaration(Output* out_h) override; 38 | void GenCode(Output* out_h, Output* out_cc) override; 39 | void GenEval(Output* out, Env* env) override; 40 | 41 | private: 42 | Type* type_; 43 | Expr* expr_; 44 | }; 45 | 46 | #endif // pac_let_h 47 | -------------------------------------------------------------------------------- /src/pac_attr.cc: -------------------------------------------------------------------------------- 1 | #include "pac_attr.h" 2 | 3 | #include "pac_expr.h" 4 | 5 | bool Attr::DoTraverse(DataDepVisitor* visitor) { 6 | if ( expr_ && ! expr_->Traverse(visitor) ) 7 | return false; 8 | return true; 9 | } 10 | 11 | bool Attr::RequiresAnalyzerContext() const { return (expr_ && expr_->RequiresAnalyzerContext()); } 12 | 13 | void Attr::init() { 14 | expr_ = nullptr; 15 | seqend_ = nullptr; 16 | delete_expr_ = false; 17 | } 18 | 19 | Attr::Attr(AttrType type) : DataDepElement(DataDepElement::ATTR) { 20 | type_ = type; 21 | init(); 22 | } 23 | 24 | Attr::Attr(AttrType type, Expr* expr) : DataDepElement(DataDepElement::ATTR) { 25 | type_ = type; 26 | init(); 27 | expr_ = expr; 28 | } 29 | 30 | Attr::Attr(AttrType type, ExprList* exprlist) : DataDepElement(DataDepElement::ATTR) { 31 | type_ = type; 32 | init(); 33 | expr_ = new Expr(exprlist); 34 | delete_expr_ = true; 35 | } 36 | 37 | Attr::Attr(AttrType type, SeqEnd* seqend) : DataDepElement(DataDepElement::ATTR) { 38 | type_ = type; 39 | init(); 40 | seqend_ = seqend; 41 | } 42 | 43 | Attr::~Attr() { 44 | if ( delete_expr_ ) 45 | delete expr_; 46 | } 47 | 48 | LetAttr::LetAttr(FieldList* letfields) : Attr(ATTR_LET) { letfields_ = letfields; } 49 | -------------------------------------------------------------------------------- /src/pac_inputbuf.cc: -------------------------------------------------------------------------------- 1 | #include "pac_inputbuf.h" 2 | 3 | #include "pac_expr.h" 4 | #include "pac_exttype.h" 5 | #include "pac_id.h" 6 | #include "pac_output.h" 7 | #include "pac_type.h" 8 | 9 | InputBuffer::InputBuffer(Expr* expr) : DataDepElement(INPUT_BUFFER), expr_(expr) {} 10 | 11 | bool InputBuffer::DoTraverse(DataDepVisitor* visitor) { 12 | if ( expr_ && ! expr_->Traverse(visitor) ) 13 | return false; 14 | return true; 15 | } 16 | 17 | bool InputBuffer::RequiresAnalyzerContext() const { return expr_->RequiresAnalyzerContext(); } 18 | 19 | DataPtr InputBuffer::GenDataBeginEnd(Output* out_cc, Env* env) { 20 | env->AddID(begin_of_data, TEMP_VAR, extern_type_const_byteptr); 21 | env->AddID(end_of_data, TEMP_VAR, extern_type_const_byteptr); 22 | 23 | out_cc->println("%s %s;", extern_type_const_byteptr->DataTypeStr().c_str(), env->LValue(begin_of_data)); 24 | out_cc->println("%s %s;", extern_type_const_byteptr->DataTypeStr().c_str(), env->LValue(end_of_data)); 25 | 26 | out_cc->println("get_pointers(%s, &%s, &%s);", expr_->EvalExpr(out_cc, env), env->LValue(begin_of_data), 27 | env->LValue(end_of_data)); 28 | 29 | env->SetEvaluated(begin_of_data); 30 | env->SetEvaluated(end_of_data); 31 | 32 | return DataPtr(env, begin_of_data, 0); 33 | } 34 | -------------------------------------------------------------------------------- /src/pac_varfield.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_varfield_h 2 | #define pac_varfield_h 3 | 4 | #include "pac_field.h" 5 | 6 | // A private variable evaluated with parsing 7 | class ParseVarField : public Field { 8 | public: 9 | ParseVarField(int is_class_member, ID* id, Type* type) 10 | : Field(PARSE_VAR_FIELD, TYPE_TO_BE_PARSED | is_class_member | NOT_PUBLIC_READABLE, id, type) {} 11 | void GenPubDecls(Output* out, Env* env) override { /* do nothing */ 12 | } 13 | }; 14 | 15 | // A public variable 16 | class PubVarField : public Field { 17 | public: 18 | PubVarField(ID* id, Type* type) 19 | : Field(PUB_VAR_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type) {} 20 | ~PubVarField() override {} 21 | }; 22 | 23 | // A private variable 24 | class PrivVarField : public Field { 25 | public: 26 | PrivVarField(ID* id, Type* type) 27 | : Field(PRIV_VAR_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | NOT_PUBLIC_READABLE, id, type) {} 28 | ~PrivVarField() override {} 29 | 30 | void GenPubDecls(Output* out, Env* env) override { /* do nothing */ 31 | } 32 | }; 33 | 34 | class TempVarField : public Field { 35 | public: 36 | TempVarField(ID* id, Type* type) : Field(TEMP_VAR_FIELD, TYPE_NOT_TO_BE_PARSED | NOT_CLASS_MEMBER, id, type) {} 37 | ~TempVarField() override {} 38 | }; 39 | 40 | #endif // pac_varfield_h 41 | -------------------------------------------------------------------------------- /src/pac_param.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_param_h 2 | #define pac_param_h 3 | 4 | #include "pac_common.h" 5 | #include "pac_field.h" 6 | 7 | class Param : public Object { 8 | public: 9 | Param(ID* id, Type* type); 10 | ~Param(); 11 | 12 | ID* id() const { return id_; } 13 | Type* type() const { return type_; } 14 | const string& decl_str() const; 15 | Field* param_field() const { return param_field_; } 16 | 17 | private: 18 | ID* id_; 19 | Type* type_; 20 | string decl_str_; 21 | Field* param_field_; 22 | }; 23 | 24 | class ParamField : public Field { 25 | public: 26 | ParamField(const Param* param); 27 | 28 | void GenInitCode(Output* out, Env* env) override; 29 | void GenCleanUpCode(Output* out, Env* env) override; 30 | }; 31 | 32 | // Returns the string with a list of param declarations separated by ','. 33 | string ParamDecls(ParamList* params); 34 | 35 | #if 0 36 | // Generate assignments to parameters, in the form of "%s_ = %s;" % (id, id). 37 | void GenParamAssignments(ParamList *params, Output *out_cc, Env *env); 38 | 39 | // Generate public access methods to parameter members. 40 | void GenParamPubDecls(ParamList *params, Output *out_h, Env *env); 41 | 42 | // Generate private definitions of parameter members. 43 | void GenParamPrivDecls(ParamList *params, Output *out_h, Env *env); 44 | #endif 45 | 46 | #endif // pac_param_h 47 | -------------------------------------------------------------------------------- /src/pac_expr.def: -------------------------------------------------------------------------------- 1 | EXPR_DEF(EXPR_ID, 0, "%s") 2 | EXPR_DEF(EXPR_NUM, 0, "%s") 3 | EXPR_DEF(EXPR_NULLPTR, 0, "%s") 4 | EXPR_DEF(EXPR_CSTR, 0, "%s") 5 | EXPR_DEF(EXPR_REGEX, 0, "REGEX(%s)") 6 | EXPR_DEF(EXPR_SUBSCRIPT, 2, "@element@(%s[%s])") 7 | EXPR_DEF(EXPR_MEMBER, 2, "@%s->%s@") 8 | EXPR_DEF(EXPR_PAREN, 1, " ( %s ) ") 9 | EXPR_DEF(EXPR_CALL, 1, "%s(%s)") 10 | EXPR_DEF(EXPR_CALLARGS, -1, "@custom@") 11 | EXPR_DEF(EXPR_SIZEOF, 1, "@sizeof(%s)@") 12 | EXPR_DEF(EXPR_OFFSETOF, 1, "@offsetof(%s)@") 13 | EXPR_DEF(EXPR_NEG, 1, "-%s") 14 | EXPR_DEF(EXPR_PLUS, 2, "%s + %s") 15 | EXPR_DEF(EXPR_MINUS, 2, "%s - %s") 16 | EXPR_DEF(EXPR_TIMES, 2, "%s * %s") 17 | EXPR_DEF(EXPR_DIV, 2, "%s / %s") 18 | EXPR_DEF(EXPR_MOD, 2, "%s %% %s") 19 | EXPR_DEF(EXPR_BITNOT, 1, "~%s") 20 | EXPR_DEF(EXPR_BITAND, 2, "%s & %s") 21 | EXPR_DEF(EXPR_BITOR, 2, "%s | %s") 22 | EXPR_DEF(EXPR_BITXOR, 2, "%s ^ %s") 23 | EXPR_DEF(EXPR_LSHIFT, 2, "%s << %s") 24 | EXPR_DEF(EXPR_RSHIFT, 2, "%s >> %s") 25 | EXPR_DEF(EXPR_EQUAL, 2, "%s == %s") 26 | EXPR_DEF(EXPR_NEQ, 2, "%s != %s") 27 | EXPR_DEF(EXPR_GE, 2, "%s >= %s") 28 | EXPR_DEF(EXPR_LE, 2, "%s <= %s") 29 | EXPR_DEF(EXPR_GT, 2, "%s > %s") 30 | EXPR_DEF(EXPR_LT, 2, "%s < %s") 31 | EXPR_DEF(EXPR_NOT, 1, "! %s") 32 | EXPR_DEF(EXPR_AND, 2, "%s && %s") 33 | EXPR_DEF(EXPR_OR, 2, "%s || %s") 34 | EXPR_DEF(EXPR_COND, 3, "%s ? %s : %s") 35 | EXPR_DEF(EXPR_CASE, -1, "@custom@") 36 | -------------------------------------------------------------------------------- /src/pac_attr.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_attr_h 2 | #define pac_attr_h 3 | 4 | #include "pac_common.h" 5 | #include "pac_datadep.h" 6 | 7 | enum AttrType { 8 | ATTR_BYTEORDER, 9 | ATTR_CHECK, 10 | ATTR_CHUNKED, 11 | ATTR_ENFORCE, 12 | ATTR_EXPORTSOURCEDATA, 13 | ATTR_IF, 14 | ATTR_LENGTH, 15 | ATTR_LET, 16 | ATTR_LINEBREAKER, 17 | ATTR_MULTILINE, 18 | ATTR_ONELINE, 19 | ATTR_REFCOUNT, 20 | ATTR_REQUIRES, 21 | ATTR_RESTOFDATA, 22 | ATTR_RESTOFFLOW, 23 | ATTR_TRANSIENT, 24 | ATTR_UNTIL, 25 | }; 26 | 27 | class Attr : public Object, public DataDepElement { 28 | public: 29 | Attr(AttrType type); 30 | Attr(AttrType type, Expr* expr); 31 | Attr(AttrType type, ExprList* exprlist); 32 | Attr(AttrType type, SeqEnd* seqend); 33 | 34 | ~Attr() override; 35 | 36 | AttrType type() const { return type_; } 37 | Expr* expr() const { return expr_; } 38 | SeqEnd* seqend() const { return seqend_; } 39 | 40 | bool RequiresAnalyzerContext() const; 41 | 42 | protected: 43 | bool DoTraverse(DataDepVisitor* visitor) override; 44 | 45 | protected: 46 | void init(); 47 | 48 | AttrType type_; 49 | Expr* expr_; 50 | SeqEnd* seqend_; 51 | bool delete_expr_; 52 | }; 53 | 54 | class LetAttr : public Attr { 55 | public: 56 | LetAttr(FieldList* letfields); 57 | FieldList* letfields() const { return letfields_; } 58 | 59 | private: 60 | FieldList* letfields_; 61 | }; 62 | 63 | #endif // pac_attr_h 64 | -------------------------------------------------------------------------------- /src/pac_btype.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_btype_h 2 | #define pac_btype_h 3 | 4 | #include "pac_type.h" 5 | 6 | class BuiltInType : public Type { 7 | public: 8 | enum BITType { 9 | #define TYPE_DEF(name, pactype, ctype, size) name, 10 | #include "pac_type.def" 11 | #undef TYPE_DEF 12 | }; 13 | 14 | static int LookUpByName(const char* name); 15 | 16 | BuiltInType(BITType bit_type) : Type(bit_type == BuiltInType::EMPTY ? Type::EMPTY : BUILTIN), bit_type_(bit_type) {} 17 | 18 | BITType bit_type() const { return bit_type_; } 19 | 20 | bool IsNumericType() const override; 21 | 22 | bool DefineValueVar() const override; 23 | string DataTypeStr() const override; 24 | string DefaultValue() const override { return "0"; } 25 | 26 | int StaticSize(Env* env) const override; 27 | 28 | bool IsPointerType() const override { return false; } 29 | 30 | bool ByteOrderSensitive() const override { return StaticSize(0) >= 2; } 31 | 32 | void GenInitCode(Output* out_cc, Env* env) override; 33 | 34 | void DoMarkIncrementalInput() override; 35 | 36 | protected: 37 | void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; 38 | void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; 39 | Type* DoClone() const override; 40 | 41 | BITType bit_type_; 42 | 43 | public: 44 | static void static_init(); 45 | static bool CompatibleBuiltInTypes(BuiltInType* type1, BuiltInType* type2); 46 | }; 47 | 48 | #endif // pac_btype_h 49 | -------------------------------------------------------------------------------- /src/pac_param.cc: -------------------------------------------------------------------------------- 1 | #include "pac_param.h" 2 | 3 | #include "pac_decl.h" 4 | #include "pac_exttype.h" 5 | #include "pac_field.h" 6 | #include "pac_id.h" 7 | #include "pac_output.h" 8 | #include "pac_type.h" 9 | #include "pac_utils.h" 10 | 11 | Param::Param(ID* id, Type* type) : id_(id), type_(type) { 12 | if ( ! type_ ) 13 | type_ = extern_type_int->Clone(); 14 | 15 | decl_str_ = strfmt("%s %s", type_->DataTypeConstRefStr().c_str(), id_->Name()); 16 | 17 | param_field_ = new ParamField(this); 18 | } 19 | 20 | Param::~Param() {} 21 | 22 | const string& Param::decl_str() const { 23 | ASSERT(! decl_str_.empty()); 24 | return decl_str_; 25 | } 26 | 27 | string ParamDecls(ParamList* params) { 28 | string param_decls; 29 | 30 | int first = 1; 31 | foreach (i, ParamList, params) { 32 | Param* p = *i; 33 | const char* decl_str = p->decl_str().c_str(); 34 | if ( first ) 35 | first = 0; 36 | else 37 | param_decls += ", "; 38 | param_decls += decl_str; 39 | } 40 | return param_decls; 41 | } 42 | 43 | ParamField::ParamField(const Param* param) 44 | : Field(PARAM_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, param->id(), param->type()) {} 45 | 46 | void ParamField::GenInitCode(Output* out_cc, Env* env) { 47 | out_cc->println("%s = %s;", env->LValue(id()), id()->Name()); 48 | env->SetEvaluated(id()); 49 | } 50 | 51 | void ParamField::GenCleanUpCode(Output* out_cc, Env* env) { 52 | // Do nothing 53 | } 54 | -------------------------------------------------------------------------------- /src/pac_flow.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_flow_h 2 | #define pac_flow_h 3 | 4 | #include "pac_analyzer.h" 5 | 6 | class FlowDecl : public AnalyzerDecl { 7 | public: 8 | FlowDecl(ID* flow_id, ParamList* params, AnalyzerElementList* elemlist); 9 | ~FlowDecl() override; 10 | 11 | void Prepare() override; 12 | 13 | void set_conn_decl(ConnDecl* c) { conn_decl_ = c; } 14 | 15 | static ParameterizedType* flow_buffer_type(); 16 | 17 | protected: 18 | void AddBaseClass(vector* base_classes) const override; 19 | 20 | void GenInitCode(Output* out_cc) override; 21 | void GenCleanUpCode(Output* out_cc) override; 22 | void GenProcessFunc(Output* out_h, Output* out_cc) override; 23 | void GenEOFFunc(Output* out_h, Output* out_cc) override; 24 | void GenGapFunc(Output* out_h, Output* out_cc) override; 25 | 26 | void GenPubDecls(Output* out_h, Output* out_cc) override; 27 | void GenPrivDecls(Output* out_h, Output* out_cc) override; 28 | 29 | void ProcessFlowElement(AnalyzerFlow* flow_elem) override; 30 | void ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) override; 31 | 32 | private: 33 | void GenNewDataUnit(Output* out_cc); 34 | void GenDeleteDataUnit(Output* out_cc); 35 | void GenCodeFlowUnit(Output* out_cc); 36 | void GenCodeDatagram(Output* out_cc); 37 | 38 | AnalyzerDataUnit* dataunit_; 39 | ConnDecl* conn_decl_; 40 | 41 | Field* flow_buffer_var_field_; 42 | 43 | static ParameterizedType* flow_buffer_type_; 44 | }; 45 | 46 | #endif // pac_flow_h 47 | -------------------------------------------------------------------------------- /src/pac_typedecl.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_typedecl_h 2 | #define pac_typedecl_h 3 | 4 | #include "pac_decl.h" 5 | 6 | class TypeDecl : public Decl { 7 | public: 8 | TypeDecl(ID* arg_id, ParamList* arg_params, Type* arg_type); 9 | ~TypeDecl() override; 10 | void Prepare() override; 11 | void GenForwardDeclaration(Output* out_h) override; 12 | void GenCode(Output* out_h, Output* out_cc) override; 13 | 14 | Env* env() const override { return env_; } 15 | Type* type() const { return type_; } 16 | string class_name() const; 17 | static Type* LookUpType(const ID* id); 18 | 19 | protected: 20 | void AddParam(Param* param); 21 | virtual void AddBaseClass(vector* base_classes) const {} 22 | void ProcessAttr(Attr* a) override; 23 | 24 | virtual void GenPubDecls(Output* out_h, Output* out_cc); 25 | virtual void GenPrivDecls(Output* out_h, Output* out_cc); 26 | virtual void GenInitCode(Output* out_cc); 27 | virtual void GenCleanUpCode(Output* out_cc); 28 | 29 | void GenConstructorFunc(Output* out_h, Output* out_cc); 30 | void GenDestructorFunc(Output* out_h, Output* out_cc); 31 | 32 | string ParseFuncPrototype(Env* env); 33 | void GenParseFunc(Output* out_h, Output* out_cc); 34 | 35 | void GenParsingEnd(Output* out_cc, Env* env, const DataPtr& data); 36 | 37 | void GenInitialBufferLengthFunc(Output* out_h, Output* out_cc); 38 | 39 | protected: 40 | Env* env_; 41 | 42 | ParamList* params_; 43 | Type* type_; 44 | }; 45 | 46 | #endif // pac_typedecl_h 47 | -------------------------------------------------------------------------------- /src/pac_dataunit.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_dataunit_h 2 | #define pac_dataunit_h 3 | 4 | #include "pac_analyzer.h" 5 | 6 | // The type and parameters of input data unit of a flow. For instance, the 7 | // data unit of a DCE/RPC flow is DCE_RPC_PDU. 8 | 9 | class AnalyzerDataUnit : public AnalyzerElement { 10 | public: 11 | enum DataUnitType { DATAGRAM, FLOWUNIT }; 12 | AnalyzerDataUnit(DataUnitType type, ID* id, ExprList* type_params, ExprList* context_params); 13 | ~AnalyzerDataUnit() override; 14 | 15 | void Prepare(Env* env); 16 | 17 | // Initializes dataunit_id 18 | void GenNewDataUnit(Output* out_cc, Env* env); 19 | // Initializes analyzer_context_id 20 | void GenNewContext(Output* out_cc, Env* env); 21 | 22 | DataUnitType type() const { return type_; } 23 | const ID* id() const { return id_; } 24 | ExprList* type_params() const { return type_params_; } 25 | ExprList* context_params() const { return context_params_; } 26 | 27 | ParameterizedType* data_type() const { return data_type_; } 28 | ParameterizedType* context_type() const { return context_type_; } 29 | 30 | Field* dataunit_var_field() const { return dataunit_var_field_; } 31 | Field* context_var_field() const { return context_var_field_; } 32 | 33 | private: 34 | DataUnitType type_; 35 | ID* id_; 36 | ExprList* type_params_; 37 | ExprList* context_params_; 38 | ParameterizedType* data_type_; 39 | ParameterizedType* context_type_; 40 | Field* dataunit_var_field_; 41 | Field* context_var_field_; 42 | }; 43 | 44 | #endif // pac_dataunit_h 45 | -------------------------------------------------------------------------------- /src/pac_output.cc: -------------------------------------------------------------------------------- 1 | #include "pac_output.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "pac_utils.h" 9 | 10 | OutputException::OutputException(const char* arg_msg) { msg = arg_msg; } 11 | 12 | OutputException::~OutputException() {} 13 | 14 | Output::Output(string filename) { 15 | fp = fopen(filename.c_str(), "w"); 16 | if ( ! fp ) 17 | throw OutputException(strerror(errno)); 18 | indent_ = 0; 19 | } 20 | 21 | Output::~Output() { 22 | if ( fp ) 23 | fclose(fp); 24 | } 25 | 26 | int Output::print(const char* fmt, va_list ap) { 27 | int r = vfprintf(fp, fmt, ap); 28 | if ( r == -1 ) 29 | throw OutputException(strerror(errno)); 30 | return r; 31 | } 32 | 33 | int Output::print(const char* fmt, ...) { 34 | va_list ap; 35 | va_start(ap, fmt); 36 | int r = -1; 37 | 38 | try { 39 | r = print(fmt, ap); 40 | } 41 | 42 | catch ( ... ) { 43 | va_end(ap); 44 | throw; 45 | } 46 | 47 | va_end(ap); 48 | return r; 49 | } 50 | 51 | int Output::println(const char* fmt, ...) { 52 | if ( strlen(fmt) == 0 ) { 53 | fprintf(fp, "\n"); 54 | return 0; 55 | } 56 | 57 | for ( int i = 0; i < indent(); ++i ) 58 | fprintf(fp, " "); 59 | 60 | va_list ap; 61 | va_start(ap, fmt); 62 | int r = -1; 63 | 64 | try { 65 | r = print(fmt, ap); 66 | } 67 | 68 | catch ( ... ) { 69 | va_end(ap); 70 | throw; 71 | } 72 | 73 | va_end(ap); 74 | fprintf(fp, "\n"); 75 | return r; 76 | } 77 | -------------------------------------------------------------------------------- /src/pac_dataunit.cc: -------------------------------------------------------------------------------- 1 | #include "pac_dataunit.h" 2 | 3 | #include "pac_context.h" 4 | #include "pac_output.h" 5 | #include "pac_paramtype.h" 6 | #include "pac_varfield.h" 7 | 8 | AnalyzerDataUnit::AnalyzerDataUnit(DataUnitType type, ID* id, ExprList* type_params, ExprList* context_params) 9 | : AnalyzerElement(DATAUNIT), type_(type), id_(id), type_params_(type_params), context_params_(context_params) { 10 | data_type_ = new ParameterizedType(id_, type_params_); 11 | context_type_ = 12 | new ParameterizedType(AnalyzerContextDecl::current_analyzer_context()->id()->clone(), context_params_); 13 | 14 | dataunit_var_field_ = new ParseVarField(Field::CLASS_MEMBER, dataunit_id->clone(), data_type()); 15 | context_var_field_ = new PrivVarField(analyzer_context_id->clone(), context_type()); 16 | } 17 | 18 | AnalyzerDataUnit::~AnalyzerDataUnit() { 19 | delete dataunit_var_field_; 20 | delete context_var_field_; 21 | } 22 | 23 | void AnalyzerDataUnit::Prepare(Env* env) { 24 | dataunit_var_field_->Prepare(env); 25 | context_var_field_->Prepare(env); 26 | } 27 | 28 | void AnalyzerDataUnit::GenNewDataUnit(Output* out_cc, Env* env) { 29 | out_cc->println("%s = new %s(%s);", env->LValue(dataunit_id), data_type()->class_name().c_str(), 30 | data_type()->EvalParameters(out_cc, env).c_str()); 31 | } 32 | 33 | void AnalyzerDataUnit::GenNewContext(Output* out_cc, Env* env) { 34 | out_cc->println("%s = new %s(%s);", env->LValue(analyzer_context_id), context_type()->class_name().c_str(), 35 | context_type()->EvalParameters(out_cc, env).c_str()); 36 | env->SetEvaluated(analyzer_context_id); 37 | } 38 | -------------------------------------------------------------------------------- /src/pac_primitive.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_primitive_h 2 | #define pac_primitive_h 3 | 4 | #include "pac_common.h" 5 | 6 | class PacPrimitive { 7 | public: 8 | enum PrimitiveType { VAL, SET, TYPE, CONST_DEF }; 9 | 10 | explicit PacPrimitive(PrimitiveType type) : type_(type) {} 11 | virtual ~PacPrimitive() {} 12 | 13 | PrimitiveType type() const { return type_; } 14 | 15 | virtual string ToCode(Env* env) = 0; 16 | 17 | private: 18 | PrimitiveType type_; 19 | }; 20 | 21 | class PPVal : public PacPrimitive { 22 | public: 23 | PPVal(Expr* expr) : PacPrimitive(VAL), expr_(expr) {} 24 | Expr* expr() const { return expr_; } 25 | 26 | string ToCode(Env* env) override; 27 | 28 | private: 29 | Expr* expr_; 30 | }; 31 | 32 | class PPSet : public PacPrimitive { 33 | public: 34 | PPSet(Expr* expr) : PacPrimitive(SET), expr_(expr) {} 35 | Expr* expr() const { return expr_; } 36 | 37 | string ToCode(Env* env) override; 38 | 39 | private: 40 | Expr* expr_; 41 | }; 42 | 43 | class PPType : public PacPrimitive { 44 | public: 45 | PPType(Expr* expr) : PacPrimitive(TYPE), expr_(expr) {} 46 | Expr* expr() const { return expr_; } 47 | 48 | string ToCode(Env* env) override; 49 | 50 | private: 51 | Expr* expr_; 52 | }; 53 | 54 | class PPConstDef : public PacPrimitive { 55 | public: 56 | PPConstDef(const ID* id, Expr* expr) : PacPrimitive(CONST_DEF), id_(id), expr_(expr) {} 57 | const ID* id() const { return id_; } 58 | Expr* expr() const { return expr_; } 59 | 60 | string ToCode(Env* env) override; 61 | 62 | private: 63 | const ID* id_; 64 | Expr* expr_; 65 | }; 66 | 67 | #endif // pac_primitive_h 68 | -------------------------------------------------------------------------------- /src/pac_exttype.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_exttype_h 2 | #define pac_exttype_h 3 | 4 | #include "pac_type.h" 5 | 6 | // ExternType represent external C++ types that are not defined in 7 | // PAC specification (therefore they cannot appear in data layout 8 | // specification, e.g., in a record field). The type name is copied 9 | // literally to the compiled code. 10 | 11 | class ExternType : public Type { 12 | public: 13 | enum EXTType { PLAIN, NUMBER, POINTER, BOOLEAN }; 14 | ExternType(const ID* id, EXTType ext_type) : Type(EXTERN), id_(id), ext_type_(ext_type) {} 15 | 16 | bool DefineValueVar() const override; 17 | string DataTypeStr() const override; 18 | int StaticSize(Env* env) const override; 19 | bool ByteOrderSensitive() const override; 20 | 21 | string EvalMember(const ID* member_id) const override; 22 | bool IsNumericType() const override { return ext_type_ == NUMBER; } 23 | bool IsPointerType() const override { return ext_type_ == POINTER; } 24 | bool IsBooleanType() const override { return ext_type_ == BOOLEAN; } 25 | 26 | void GenInitCode(Output* out_cc, Env* env) override; 27 | 28 | protected: 29 | void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; 30 | void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; 31 | 32 | Type* DoClone() const override; 33 | 34 | private: 35 | const ID* id_; 36 | EXTType ext_type_; 37 | 38 | public: 39 | static void static_init(); 40 | }; 41 | 42 | #define EXTERNTYPE(name, ctype, exttype) extern ExternType* extern_type_##name; 43 | #include "pac_externtype.def" 44 | #undef EXTERNTYPE 45 | 46 | #endif // pac_exttype_h 47 | -------------------------------------------------------------------------------- /src/pac_enum.cc: -------------------------------------------------------------------------------- 1 | #include "pac_enum.h" 2 | 3 | #include "pac_exception.h" 4 | #include "pac_expr.h" 5 | #include "pac_exttype.h" 6 | #include "pac_output.h" 7 | #include "pac_typedecl.h" 8 | 9 | Enum::Enum(ID* id, Expr* expr) : id_(id), expr_(expr) {} 10 | 11 | Enum::~Enum() { 12 | delete id_; 13 | delete expr_; 14 | } 15 | 16 | void Enum::GenHeader(Output* out_h, int* pval) { 17 | ASSERT(pval); 18 | if ( expr_ ) { 19 | if ( ! expr_->ConstFold(global_env(), pval) ) 20 | throw ExceptionNonConstExpr(expr_); 21 | out_h->println("%s = %d,", id_->Name(), *pval); 22 | } 23 | else 24 | out_h->println("%s,", id_->Name()); 25 | global_env()->AddConstID(id_, *pval); 26 | } 27 | 28 | EnumDecl::EnumDecl(ID* id, EnumList* enumlist) : Decl(id, ENUM), enumlist_(enumlist) { 29 | ID* type_id = id->clone(); 30 | datatype_ = new ExternType(type_id, ExternType::NUMBER); 31 | extern_typedecl_ = new TypeDecl(type_id, nullptr, datatype_); 32 | } 33 | 34 | EnumDecl::~EnumDecl() { 35 | delete_list(EnumList, enumlist_); 36 | delete extern_typedecl_; 37 | } 38 | 39 | void EnumDecl::Prepare() { 40 | // Do nothing 41 | } 42 | 43 | void EnumDecl::GenForwardDeclaration(Output* out_h) { 44 | out_h->println("// NOLINTNEXTLINE(performance-enum-size)"); 45 | out_h->println("enum %s {", id_->Name()); 46 | out_h->inc_indent(); 47 | int c = 0; 48 | foreach (i, EnumList, enumlist_) { 49 | (*i)->GenHeader(out_h, &c); 50 | ++c; 51 | } 52 | out_h->dec_indent(); 53 | out_h->println("};"); 54 | } 55 | 56 | void EnumDecl::GenCode(Output* out_h, Output* /* out_cc */) { 57 | // Do nothing 58 | } 59 | -------------------------------------------------------------------------------- /src/pac_func.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_func_h 2 | #define pac_func_h 3 | 4 | #include "pac_analyzer.h" 5 | #include "pac_decl.h" 6 | 7 | class Function : public Object { 8 | public: 9 | Function(ID* id, Type* type, ParamList* params); 10 | ~Function(); 11 | 12 | ID* id() const { return id_; } 13 | 14 | AnalyzerDecl* analyzer_decl() const { return analyzer_decl_; } 15 | void set_analyzer_decl(AnalyzerDecl* decl) { analyzer_decl_ = decl; } 16 | 17 | Expr* expr() const { return expr_; } 18 | void set_expr(Expr* expr) { expr_ = expr; } 19 | 20 | EmbeddedCode* code() const { return code_; } 21 | void set_code(EmbeddedCode* code) { code_ = code; } 22 | 23 | void Prepare(Env* env); 24 | void GenForwardDeclaration(Output* out_h); 25 | void GenCode(Output* out_h, Output* out_cc); 26 | 27 | private: 28 | Env* env_; 29 | 30 | ID* id_; 31 | Type* type_; 32 | ParamList* params_; 33 | 34 | AnalyzerDecl* analyzer_decl_; 35 | 36 | Expr* expr_; 37 | EmbeddedCode* code_; 38 | }; 39 | 40 | class FuncDecl : public Decl { 41 | public: 42 | FuncDecl(Function* function); 43 | ~FuncDecl() override; 44 | 45 | Function* function() const { return function_; } 46 | 47 | void Prepare() override; 48 | void GenForwardDeclaration(Output* out_h) override; 49 | void GenCode(Output* out_h, Output* out_cc) override; 50 | 51 | private: 52 | Function* function_; 53 | }; 54 | 55 | class AnalyzerFunction : public AnalyzerElement { 56 | public: 57 | AnalyzerFunction(Function* function); 58 | 59 | Function* function() const { return function_; } 60 | 61 | private: 62 | Function* function_; 63 | }; 64 | 65 | #endif // pac_func_h 66 | -------------------------------------------------------------------------------- /src/pac_cclass.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_cclass_h 2 | #define pac_cclass_h 3 | 4 | class CClass; 5 | class CClassMember; 6 | class CClassMethod; 7 | class CType; 8 | class CVariable; 9 | 10 | typedef vector CClassMemberList; 11 | typedef vector CClassMethodList; 12 | typedef vector CVariableList; 13 | 14 | #include "pac_common.h" 15 | 16 | // Represents a C++ class. 17 | // 18 | // For now we adopt a simple model: 19 | // 20 | // 1. All members have a protected member variable "name_" and a 21 | // public constant access method "name()". 22 | // 23 | // 2. All methods are public. 24 | // 25 | // 3. We do not check repeated names. 26 | 27 | class CClass { 28 | public: 29 | CClass(const string& class_name); 30 | 31 | void AddMember(CClassMember* member); 32 | void AddMethod(CClassMember* method); 33 | 34 | void GenForwardDeclaration(Output* out_h); 35 | void GenCode(Output* out_h, Output* out_cc); 36 | 37 | protected: 38 | string class_name_; 39 | CClassMemberList* members_; 40 | CClassMethodList* methods_; 41 | }; 42 | 43 | class CVariable { 44 | public: 45 | CClassMember(const string& name, CType* type); 46 | 47 | string name() const { return name_; } 48 | CType* type() const { return type_; } 49 | 50 | protected: 51 | string name_; 52 | CType* type_; 53 | }; 54 | 55 | class CClassMember { 56 | public: 57 | CClassMember(CVariable* var); 58 | void GenCode(Output* out_h, Output* out_cc); 59 | 60 | string decl() const; 61 | 62 | protected: 63 | CVariable* var_; 64 | }; 65 | 66 | class CClassMethod { 67 | public: 68 | CClassMethod(CVariable* var, CVariableList* params); 69 | 70 | string decl() const; 71 | 72 | protected: 73 | CVariable* var_; 74 | CVariableList* params_; 75 | }; 76 | 77 | #endif // pac_cclass_h 78 | -------------------------------------------------------------------------------- /src/pac_datadep.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_datadep_h 2 | #define pac_datadep_h 3 | 4 | // To provide a way to traverse through the data dependency graph. 5 | // That is, to evaluate X, what must be evaluated. 6 | 7 | #include "pac_common.h" 8 | #include "pac_dbg.h" 9 | 10 | class DataDepVisitor; 11 | 12 | class DataDepElement { 13 | public: 14 | enum DDE_Type { 15 | ATTR, 16 | CASEEXPR, 17 | EXPR, 18 | FIELD, 19 | INPUT_BUFFER, 20 | PARAM, 21 | TYPE, 22 | }; 23 | 24 | DataDepElement(DDE_Type type); 25 | virtual ~DataDepElement() {} 26 | 27 | // Returns whether to continue traversal 28 | bool Traverse(DataDepVisitor* visitor); 29 | 30 | // Returns whether to continue traversal 31 | virtual bool DoTraverse(DataDepVisitor* visitor) = 0; 32 | 33 | DDE_Type dde_type() const { return dde_type_; } 34 | Expr* expr(); 35 | Type* type(); 36 | 37 | protected: 38 | DDE_Type dde_type_; 39 | bool in_traversal; 40 | }; 41 | 42 | class DataDepVisitor { 43 | public: 44 | virtual ~DataDepVisitor() {} 45 | // Returns whether to continue traversal 46 | virtual bool PreProcess(DataDepElement* element) = 0; 47 | virtual bool PostProcess(DataDepElement* element) = 0; 48 | }; 49 | 50 | class RequiresAnalyzerContext : public DataDepVisitor { 51 | public: 52 | RequiresAnalyzerContext() : requires_analyzer_context_(false) {} 53 | 54 | // Returns whether to continue traversal 55 | bool PreProcess(DataDepElement* element) override; 56 | bool PostProcess(DataDepElement* element) override; 57 | 58 | bool requires_analyzer_context() const { return requires_analyzer_context_; } 59 | 60 | static bool compute(DataDepElement* element); 61 | 62 | protected: 63 | void ProcessExpr(Expr* expr); 64 | 65 | bool requires_analyzer_context_; 66 | }; 67 | 68 | #endif // pac_datadep_h 69 | -------------------------------------------------------------------------------- /src/pac_dataptr.cc: -------------------------------------------------------------------------------- 1 | #include "pac_dataptr.h" 2 | 3 | #include "pac_exception.h" 4 | #include "pac_id.h" 5 | #include "pac_output.h" 6 | #include "pac_utils.h" 7 | 8 | DataPtr::DataPtr(Env* env, const ID* id, const int offset) : id_(id), offset_(offset) { 9 | if ( id_ ) { 10 | if ( ! env->Evaluated(id_) ) 11 | throw ExceptionIDNotEvaluated(id_); 12 | 13 | if ( offset_ == 0 ) 14 | ptr_expr_ = strfmt("%s", env->RValue(id_)); 15 | else 16 | ptr_expr_ = strfmt("(%s + %d)", env->RValue(id_), offset_); 17 | } 18 | else 19 | ptr_expr_ = "(null id)"; 20 | } 21 | 22 | int DataPtr::AbsOffset(const ID* base_ptr) const { return (id() == base_ptr) ? offset() : -1; } 23 | 24 | char* DataPtr::AbsOffsetExpr(Env* env, const ID* base_ptr) const { 25 | if ( AbsOffset(base_ptr) >= 0 ) 26 | return nfmt("%d", offset()); 27 | else 28 | return nfmt("(%s - %s)", ptr_expr(), env->RValue(base_ptr)); 29 | } 30 | 31 | void DataPtr::GenBoundaryCheck(Output* out_cc, Env* env, const char* data_size, const char* data_name) const { 32 | ASSERT(id_); 33 | 34 | out_cc->println("// Checking out-of-bound for \"%s\"", data_name); 35 | out_cc->println("if ( %s + (%s) > %s || %s + (%s) < %s ) {", ptr_expr(), data_size, env->RValue(end_of_data), 36 | ptr_expr(), data_size, ptr_expr()); 37 | 38 | out_cc->inc_indent(); 39 | 40 | char* data_offset = AbsOffsetExpr(env, begin_of_data); 41 | 42 | out_cc->println("// Handle out-of-bound condition"); 43 | out_cc->println("throw binpac::ExceptionOutOfBound(\"%s\",", data_name); 44 | out_cc->println(" (%s) + (%s), ", data_offset, data_size); 45 | out_cc->println(" (%s) - (%s));", env->RValue(end_of_data), env->RValue(begin_of_data)); 46 | 47 | delete[] data_offset; 48 | 49 | out_cc->dec_indent(); 50 | out_cc->println("}"); 51 | } 52 | -------------------------------------------------------------------------------- /src/pac_action.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_action_h 2 | #define pac_action_h 3 | 4 | // Classes representing analyzer actions. 5 | 6 | #include "pac_analyzer.h" 7 | #include "pac_common.h" 8 | 9 | class AnalyzerAction : public AnalyzerElement { 10 | public: 11 | enum When { BEFORE, AFTER }; 12 | 13 | AnalyzerAction(ID* action_id, When when, ActionParam* param, EmbeddedCode* code); 14 | 15 | ~AnalyzerAction() override; 16 | 17 | When when() const { return when_; } 18 | ActionParam* param() const { return param_; } 19 | AnalyzerDecl* analyzer() const { return analyzer_; } 20 | string action_function() const; 21 | 22 | // Generate function prototype and code for the action 23 | void GenCode(Output* out_h, Output* out_cc, AnalyzerDecl* decl); 24 | 25 | // Install the hook at the corresponding data type parsing 26 | // function to invoke the action. 27 | void InstallHook(AnalyzerDecl* analyzer); 28 | 29 | private: 30 | string ParamDecls(Env* env) const; 31 | 32 | ID* action_id_; 33 | When when_; 34 | ActionParam* param_; 35 | EmbeddedCode* code_; 36 | AnalyzerDecl* analyzer_; 37 | }; 38 | 39 | class ActionParam { 40 | public: 41 | ActionParam(const ID* id, ActionParamType* type) : id_(id), type_(type) {} 42 | 43 | const ID* id() const { return id_; } 44 | ActionParamType* type() const { return type_; } 45 | 46 | Type* MainDataType() const; 47 | Type* DataType() const; 48 | string DeclStr(Env* env) const; 49 | 50 | private: 51 | const ID* id_; 52 | ActionParamType* type_; 53 | }; 54 | 55 | class ActionParamType { 56 | public: 57 | ActionParamType(const ID* type_id, const ID* field_id = 0) : type_id_(type_id), field_id_(field_id) {} 58 | 59 | const ID* type_id() const { return type_id_; } 60 | const ID* field_id() const { return field_id_; } 61 | 62 | protected: 63 | const ID *type_id_, *field_id_; 64 | }; 65 | 66 | #endif // pac_action_h 67 | -------------------------------------------------------------------------------- /src/pac_datadep.cc: -------------------------------------------------------------------------------- 1 | #include "pac_datadep.h" 2 | 3 | #include "pac_expr.h" 4 | #include "pac_id.h" 5 | #include "pac_type.h" 6 | 7 | DataDepElement::DataDepElement(DDE_Type type) : dde_type_(type), in_traversal(false) {} 8 | 9 | bool DataDepElement::Traverse(DataDepVisitor* visitor) { 10 | // Avoid infinite loop 11 | if ( in_traversal ) 12 | return true; 13 | if ( ! visitor->PreProcess(this) ) 14 | return false; 15 | 16 | in_traversal = true; 17 | bool cont = DoTraverse(visitor); 18 | in_traversal = false; 19 | 20 | if ( ! cont ) 21 | return false; 22 | if ( ! visitor->PostProcess(this) ) 23 | return false; 24 | return true; 25 | } 26 | 27 | Expr* DataDepElement::expr() { return static_cast(this); } 28 | 29 | Type* DataDepElement::type() { return static_cast(this); } 30 | 31 | bool RequiresAnalyzerContext::PreProcess(DataDepElement* element) { 32 | switch ( element->dde_type() ) { 33 | case DataDepElement::EXPR: ProcessExpr(element->expr()); break; 34 | default: break; 35 | } 36 | 37 | // Continue traversal until we know the answer is 'yes' 38 | return ! requires_analyzer_context_; 39 | } 40 | 41 | bool RequiresAnalyzerContext::PostProcess(DataDepElement* element) { return ! requires_analyzer_context_; } 42 | 43 | void RequiresAnalyzerContext::ProcessExpr(Expr* expr) { 44 | if ( expr->expr_type() == Expr::EXPR_ID ) { 45 | requires_analyzer_context_ = 46 | (requires_analyzer_context_ || *expr->id() == *analyzer_context_id || *expr->id() == *context_macro_id); 47 | } 48 | } 49 | 50 | bool RequiresAnalyzerContext::compute(DataDepElement* element) { 51 | RequiresAnalyzerContext visitor; 52 | // This result is intentionally ignored. We want to traverse, but always return 53 | // the same result. 54 | std::ignore = element->Traverse(&visitor); 55 | return visitor.requires_analyzer_context_; 56 | } 57 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 1995-2013, The Regents of the University of California 2 | through the Lawrence Berkeley National Laboratory and the 3 | International Computer Science Institute. All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | (1) Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | (2) Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | (3) Neither the name of the University of California, Lawrence Berkeley 16 | National Laboratory, U.S. Dept. of Energy, International Computer 17 | Science Institute, nor the names of contributors may be used to endorse 18 | or promote products derived from this software without specific prior 19 | written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | POSSIBILITY OF SUCH DAMAGE. 32 | 33 | Note that some files in the distribution may carry their own copyright 34 | notices. 35 | -------------------------------------------------------------------------------- /src/pac_paramtype.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_paramtype_h 2 | #define pac_paramtype_h 3 | 4 | #include "pac_type.h" 5 | 6 | // An instantiated type: ID + expression list 7 | class ParameterizedType : public Type { 8 | public: 9 | ParameterizedType(ID* type_id, ExprList* args); 10 | ~ParameterizedType() override; 11 | 12 | Type* clone() const; 13 | 14 | string EvalMember(const ID* member_id) const override; 15 | // Env *member_env() const; 16 | 17 | void AddParamArg(Expr* arg); 18 | 19 | bool DefineValueVar() const override; 20 | string DataTypeStr() const override; 21 | string DefaultValue() const override { return "0"; } 22 | Type* MemberDataType(const ID* member_id) const override; 23 | 24 | // "throw_exception" specifies whether to throw an exception 25 | // if the referred data type is not found 26 | Type* ReferredDataType(bool throw_exception) const; 27 | 28 | void GenCleanUpCode(Output* out, Env* env) override; 29 | 30 | int StaticSize(Env* env) const override; 31 | 32 | bool IsPointerType() const override { return true; } 33 | 34 | bool ByteOrderSensitive() const override; 35 | bool RequiresAnalyzerContext() override; 36 | 37 | void GenInitCode(Output* out_cc, Env* env) override; 38 | 39 | string class_name() const; 40 | string EvalParameters(Output* out_cc, Env* env) const; 41 | 42 | BufferMode buffer_mode() const override; 43 | 44 | protected: 45 | void GenNewInstance(Output* out, Env* env) override; 46 | 47 | bool DoTraverse(DataDepVisitor* visitor) override; 48 | Type* DoClone() const override; 49 | void DoMarkIncrementalInput() override; 50 | 51 | private: 52 | ID* type_id_; 53 | ExprList* args_; 54 | bool checking_requires_analyzer_context_; 55 | 56 | void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; 57 | void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; 58 | }; 59 | 60 | #endif // pac_paramtype_h 61 | -------------------------------------------------------------------------------- /src/pac_embedded.cc: -------------------------------------------------------------------------------- 1 | #include "pac_embedded.h" 2 | 3 | #include "pac_id.h" 4 | #include "pac_output.h" 5 | #include "pac_primitive.h" 6 | 7 | EmbeddedCodeSegment::EmbeddedCodeSegment(const string& s) : s_(s), primitive_(nullptr) {} 8 | 9 | EmbeddedCodeSegment::EmbeddedCodeSegment(PacPrimitive* primitive) : s_(""), primitive_(primitive) {} 10 | 11 | EmbeddedCodeSegment::~EmbeddedCodeSegment() { delete primitive_; } 12 | 13 | string EmbeddedCodeSegment::ToCode(Env* env) { 14 | if ( primitive_ && s_.empty() ) 15 | s_ = primitive_->ToCode(env); 16 | return s_; 17 | } 18 | 19 | EmbeddedCode::EmbeddedCode() { segments_ = new EmbeddedCodeSegmentList(); } 20 | 21 | EmbeddedCode::~EmbeddedCode() { delete_list(EmbeddedCodeSegmentList, segments_); } 22 | 23 | void EmbeddedCode::Append(int atom) { current_segment_ += static_cast(atom); } 24 | 25 | void EmbeddedCode::Append(const char* str) { current_segment_ += str; } 26 | 27 | void EmbeddedCode::Append(PacPrimitive* primitive) { 28 | if ( ! current_segment_.empty() ) { 29 | segments_->push_back(new EmbeddedCodeSegment(current_segment_)); 30 | current_segment_ = ""; 31 | } 32 | segments_->push_back(new EmbeddedCodeSegment(primitive)); 33 | } 34 | 35 | void EmbeddedCode::GenCode(Output* out, Env* env) { 36 | if ( ! current_segment_.empty() ) { 37 | segments_->push_back(new EmbeddedCodeSegment(current_segment_)); 38 | current_segment_ = ""; 39 | } 40 | 41 | // TODO: return to the generated file after embedded code 42 | // out->print("#line %d \"%s\"\n", line_num, filename.c_str()); 43 | 44 | // Allow use of RValue for undefined ID, in which case the 45 | // ID's name is used as its RValue 46 | env->set_allow_undefined_id(true); 47 | 48 | foreach (i, EmbeddedCodeSegmentList, segments_) { 49 | EmbeddedCodeSegment* segment = *i; 50 | out->print("%s", segment->ToCode(env).c_str()); 51 | } 52 | 53 | env->set_allow_undefined_id(false); 54 | out->print("\n"); 55 | } 56 | -------------------------------------------------------------------------------- /src/pac_withinput.cc: -------------------------------------------------------------------------------- 1 | #include "pac_withinput.h" 2 | 3 | #include "pac_dataptr.h" 4 | #include "pac_expr.h" 5 | #include "pac_inputbuf.h" 6 | #include "pac_output.h" 7 | #include "pac_type.h" 8 | 9 | WithInputField::WithInputField(ID* id, Type* type, InputBuffer* input) 10 | : Field(WITHINPUT_FIELD, TYPE_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type), input_(input) { 11 | ASSERT(type_); 12 | ASSERT(input_); 13 | } 14 | 15 | WithInputField::~WithInputField() { delete input_; } 16 | 17 | bool WithInputField::DoTraverse(DataDepVisitor* visitor) { 18 | return Field::DoTraverse(visitor) && input()->Traverse(visitor); 19 | } 20 | 21 | bool WithInputField::RequiresAnalyzerContext() const { 22 | return Field::RequiresAnalyzerContext() || (input() && input()->RequiresAnalyzerContext()); 23 | } 24 | 25 | void WithInputField::Prepare(Env* env) { 26 | Field::Prepare(env); 27 | env->SetEvalMethod(id_, this); 28 | } 29 | 30 | void WithInputField::GenEval(Output* out_cc, Env* env) { 31 | GenParseCode(out_cc, env); 32 | if ( type_->attr_if_expr() ) { 33 | out_cc->println("BINPAC_ASSERT(%s);", env->RValue(type_->has_value_var())); 34 | } 35 | } 36 | 37 | void WithInputField::GenParseCode(Output* out_cc, Env* env) { 38 | out_cc->println("// Parse \"%s\"", id_->Name()); 39 | if ( type_->attr_if_expr() ) { 40 | // A conditional field 41 | env->Evaluate(out_cc, type_->has_value_var()); 42 | out_cc->println("if ( %s ) {", env->RValue(type_->has_value_var())); 43 | out_cc->inc_indent(); 44 | } 45 | else 46 | out_cc->println("{"); 47 | 48 | Env field_env(env, this); 49 | ASSERT(! type_->incremental_input()); 50 | type_->GenPreParsing(out_cc, &field_env); 51 | type_->GenParseCode(out_cc, &field_env, input()->GenDataBeginEnd(out_cc, &field_env), 0); 52 | 53 | if ( type_->attr_if_expr() ) { 54 | out_cc->dec_indent(); 55 | out_cc->println("}"); 56 | } 57 | else 58 | out_cc->println("}"); 59 | } 60 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(TestBigEndian) 2 | test_big_endian(HOST_BIGENDIAN) 3 | 4 | include(CheckTypeSize) 5 | check_type_size("unsigned int" SIZEOF_UNSIGNED_INT) 6 | 7 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/binpac.h.in ${CMAKE_CURRENT_BINARY_DIR}/binpac.h) 8 | 9 | include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) 10 | set(binpac_headers ${CMAKE_CURRENT_BINARY_DIR}/binpac.h binpac_analyzer.h binpac_buffer.h 11 | binpac_bytestring.h binpac_exception.h binpac_regex.h) 12 | 13 | set(binpac_lib_SRCS binpac_buffer.cc binpac_bytestring.cc binpac_regex.cc ${binpac_headers}) 14 | 15 | if (ENABLE_SHARED) 16 | add_library(binpac_lib SHARED ${binpac_lib_SRCS}) 17 | set_target_properties( 18 | binpac_lib 19 | PROPERTIES SOVERSION ${BINPAC_SOVERSION} 20 | VERSION ${BINPAC_VERSION_MAJOR}.${BINPAC_VERSION_MINOR} 21 | MACOSX_RPATH true 22 | OUTPUT_NAME binpac) 23 | install(TARGETS binpac_lib DESTINATION ${CMAKE_INSTALL_LIBDIR}) 24 | endif () 25 | 26 | if (ENABLE_STATIC) 27 | add_library(binpac_static STATIC ${binpac_lib_SRCS}) 28 | set_target_properties(binpac_static PROPERTIES OUTPUT_NAME binpac) 29 | install(TARGETS binpac_static DESTINATION ${CMAKE_INSTALL_LIBDIR}) 30 | endif () 31 | 32 | if (ZEEK_ROOT_DIR) 33 | # Installed in binpac subdir just for organization purposes. 34 | install(FILES ${binpac_headers} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/binpac) 35 | else () 36 | install(FILES ${binpac_headers} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 37 | endif () 38 | 39 | # This is set to assist superprojects that want to build BinPac from source and 40 | # rely on it as a target 41 | if (ENABLE_SHARED) 42 | set(BinPAC_LIBRARY binpac_lib CACHE STRING "BinPAC library" FORCE) 43 | else () 44 | set(BinPAC_LIBRARY binpac_static CACHE STRING "BinPAC library" FORCE) 45 | endif () 46 | 47 | set(BinPAC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} 48 | CACHE STRING "BinPAC header directories" FORCE) 49 | -------------------------------------------------------------------------------- /src/pac_regex.cc: -------------------------------------------------------------------------------- 1 | #include "pac_regex.h" 2 | 3 | #include "pac_exttype.h" 4 | #include "pac_id.h" 5 | #include "pac_output.h" 6 | #include "pac_type.h" 7 | 8 | // Depends on the regular expression library we are using 9 | const char* RegEx::kREMatcherType = "RegExMatcher"; 10 | const char* RegEx::kMatchPrefix = "MatchPrefix"; 11 | 12 | string escape_char(const string& s) { 13 | char* buf = new char[s.length() * 2 + 1]; 14 | int j = 0; 15 | for ( int i = 0; i < (int)s.length(); ++i ) { 16 | if ( s[i] == '\\' ) { 17 | if ( i + 1 < (int)s.length() ) { 18 | buf[j++] = '\\'; 19 | if ( s[i + 1] == '/' ) 20 | buf[j - 1] = s[++i]; 21 | else if ( s[i + 1] == '/' || s[i + 1] == '\\' || s[i + 1] == '"' ) 22 | buf[j++] = s[++i]; 23 | else 24 | buf[j++] = '\\'; 25 | } 26 | } 27 | else if ( s[i] == '"' ) { 28 | buf[j++] = '\\'; 29 | buf[j++] = '"'; 30 | } 31 | else { 32 | buf[j++] = s[i]; 33 | } 34 | } 35 | 36 | buf[j++] = '\0'; 37 | 38 | string rval = buf; 39 | delete[] buf; 40 | return rval; 41 | } 42 | 43 | RegEx::RegEx(const string& s) { 44 | str_ = escape_char(s); 45 | string prefix = strfmt("%s_re_", current_decl_id->Name()); 46 | matcher_id_ = ID::NewAnonymousID(prefix); 47 | decl_ = new RegExDecl(this); 48 | } 49 | 50 | RegEx::~RegEx() {} 51 | 52 | RegExDecl::RegExDecl(RegEx* regex) : Decl(regex->matcher_id(), REGEX) { regex_ = regex; } 53 | 54 | void RegExDecl::Prepare() { global_env()->AddID(id(), GLOBAL_VAR, extern_type_re_matcher); } 55 | 56 | void RegExDecl::GenForwardDeclaration(Output* out_h) { 57 | out_h->println("extern %s %s;\n", RegEx::kREMatcherType, global_env()->LValue(regex_->matcher_id())); 58 | } 59 | 60 | void RegExDecl::GenCode(Output* out_h, Output* out_cc) { 61 | out_cc->println("%s %s(\"%s\");\n", RegEx::kREMatcherType, global_env()->LValue(regex_->matcher_id()), 62 | regex_->str().c_str()); 63 | } 64 | -------------------------------------------------------------------------------- /lib/binpac_regex.h: -------------------------------------------------------------------------------- 1 | #ifndef binpac_regex_h 2 | #define binpac_regex_h 3 | 4 | #include "zeek/RE.h" 5 | 6 | #include "binpac.h" 7 | 8 | namespace zeek { 9 | class RE_Matcher; 10 | } 11 | 12 | namespace binpac { 13 | 14 | // Must be called before any binpac functionality is used. 15 | // 16 | // Note, this must be declared/defined here, and inline, because the RE 17 | // functionality can only be used when compiling from inside Zeek. 18 | // A copy is made of any FlowBuffer policy struct data passed. 19 | inline void init(FlowBuffer::Policy* fbp = 0); 20 | 21 | // Internal vector recording not yet compiled matchers. 22 | extern std::vector* uncompiled_re_matchers; 23 | 24 | class RegExMatcher { 25 | public: 26 | RegExMatcher(const char* pattern) : pattern_(pattern) { 27 | if ( ! uncompiled_re_matchers ) 28 | uncompiled_re_matchers = new std::vector; 29 | 30 | re_matcher_ = new zeek::RE_Matcher(pattern_.c_str()); 31 | uncompiled_re_matchers->push_back(re_matcher_); 32 | } 33 | 34 | ~RegExMatcher() { delete re_matcher_; } 35 | 36 | // Returns the length of longest match, or -1 on mismatch. 37 | int MatchPrefix(const_byteptr data, int len) { return re_matcher_->MatchPrefix(data, len); } 38 | 39 | private: 40 | friend void ::binpac::init(FlowBuffer::Policy*); 41 | 42 | // Function, and state, for compiling matchers. 43 | static void init(); 44 | 45 | string pattern_; 46 | zeek::RE_Matcher* re_matcher_; 47 | }; 48 | 49 | inline void RegExMatcher::init() { 50 | if ( ! uncompiled_re_matchers ) 51 | return; 52 | 53 | for ( size_t i = 0; i < uncompiled_re_matchers->size(); ++i ) { 54 | if ( ! (*uncompiled_re_matchers)[i]->Compile() ) { 55 | fprintf(stderr, "binpac: cannot compile regular expression\n"); 56 | exit(1); 57 | } 58 | } 59 | 60 | uncompiled_re_matchers->clear(); 61 | } 62 | 63 | inline void init(FlowBuffer::Policy* fbp) { 64 | RegExMatcher::init(); 65 | 66 | if ( fbp ) 67 | FlowBuffer::init(*fbp); 68 | } 69 | 70 | } // namespace binpac 71 | 72 | #endif // binpac_regex_h 73 | -------------------------------------------------------------------------------- /src/pac_field.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_field_h 2 | #define pac_field_h 3 | 4 | #include "pac_common.h" 5 | #include "pac_datadep.h" 6 | 7 | // A "field" is a member of class. 8 | 9 | enum FieldType { 10 | CASE_FIELD, 11 | CONTEXT_FIELD, 12 | FLOW_FIELD, 13 | LET_FIELD, 14 | PADDING_FIELD, 15 | PARAM_FIELD, 16 | RECORD_FIELD, 17 | PARSE_VAR_FIELD, 18 | PRIV_VAR_FIELD, 19 | PUB_VAR_FIELD, 20 | TEMP_VAR_FIELD, 21 | WITHINPUT_FIELD, 22 | }; 23 | 24 | class Field : public Object, public DataDepElement { 25 | public: 26 | Field(FieldType tof, int flags, ID* id, Type* type); 27 | // Field flags 28 | 29 | // Whether the field will be evaluated by calling the Parse() 30 | // function of the type 31 | static const int TYPE_TO_BE_PARSED = 1; 32 | static const int TYPE_NOT_TO_BE_PARSED = 0; 33 | 34 | // Whether the field is a member of the class or a temp 35 | // variable 36 | static const int CLASS_MEMBER = 2; 37 | static const int NOT_CLASS_MEMBER = 0; 38 | 39 | // Whether the field is public readable 40 | static const int PUBLIC_READABLE = 4; 41 | static const int NOT_PUBLIC_READABLE = 0; 42 | 43 | ~Field() override; 44 | 45 | FieldType tof() const { return tof_; } 46 | const ID* id() const { return id_; } 47 | Type* type() const { return type_; } 48 | const ID* decl_id() const { return decl_id_; } 49 | 50 | bool anonymous_field() const; 51 | 52 | void AddAttr(AttrList* attrs); 53 | 54 | // The field interface 55 | virtual void ProcessAttr(Attr* attr); 56 | virtual void Prepare(Env* env); 57 | 58 | virtual void GenPubDecls(Output* out, Env* env); 59 | virtual void GenPrivDecls(Output* out, Env* env); 60 | virtual void GenTempDecls(Output* out, Env* env); 61 | 62 | virtual void GenInitCode(Output* out, Env* env); 63 | virtual void GenCleanUpCode(Output* out, Env* env); 64 | 65 | virtual bool RequiresAnalyzerContext() const; 66 | 67 | protected: 68 | int ValueVarType() const; 69 | bool ToBeParsed() const; 70 | 71 | bool DoTraverse(DataDepVisitor* visitor) override; 72 | 73 | protected: 74 | FieldType tof_; 75 | int flags_; 76 | ID* id_; 77 | Type* type_; 78 | const ID* decl_id_; 79 | string field_id_str_; 80 | AttrList* attrs_; 81 | }; 82 | 83 | #endif // pac_field_h 84 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # A simple static wrapper for a number of standard Makefile targets, 3 | # mostly just forwarding to build/Makefile. This is provided only for 4 | # convenience and supports only a subset of what CMake's Makefile 5 | # to offer. For more, execute that one directly. 6 | # 7 | 8 | BUILD=build 9 | REPO=$$(cd $(CURDIR) && basename $$(git config --get remote.origin.url | sed 's/^[^:]*://g')) 10 | VERSION_FULL=$(REPO)-$$(cd $(CURDIR) && cat VERSION) 11 | VERSION_MIN=$(REPO)-$$(cd $(CURDIR) && cat VERSION)-minimal 12 | GITDIR=$$(test -f .git && echo $$(cut -d" " -f2 .git) || echo .git) 13 | 14 | all: configured 15 | $(MAKE) -C $(BUILD) $@ 16 | 17 | install: configured 18 | $(MAKE) -C $(BUILD) $@ 19 | 20 | clean: configured 21 | $(MAKE) -C $(BUILD) $@ 22 | 23 | # The COPYFILE_DISABLE flag used in the tar command below is an undocumented feature 24 | # of the tar binary on macOS. It causes tar to avoid including any of the special files 25 | # that macOS litters around the repository directory, such as ._ resource files, none 26 | # of which should be included in the distribution packages. 27 | dist: 28 | @test -e ../$(VERSION_FULL) && rm -ri ../$(VERSION_FULL) || true 29 | @cp -R . ../$(VERSION_FULL) 30 | @for i in . $$(git submodule foreach -q --recursive realpath --relative-to=$$(pwd) .); do ((cd ../$(VERSION_FULL)/$$i && test -f .git && cp -R $(GITDIR) .gitnew && rm -f .git && mv .gitnew .git && sed -i.bak -e 's#[[:space:]]*worktree[[:space:]]*=[[:space:]]*.*##g' .git/config) || true); done 31 | @for i in . $$(git submodule foreach -q --recursive realpath --relative-to=$$(pwd) .); do (cd ../$(VERSION_FULL)/$$i && git reset -q --hard && git clean -ffdxq); done 32 | @(cd ../$(VERSION_FULL) && find . -name \.git\* | xargs rm -rf) 33 | @(cd ../$(VERSION_FULL) && find . -name \.idea -type d | xargs rm -rf) 34 | @(cd ../$(VERSION_FULL) && find . -maxdepth 1 -name build\* | xargs rm -rf) 35 | @mv ../$(VERSION_FULL) . 36 | @COPYFILE_DISABLE=true tar -czf $(VERSION_FULL).tar.gz $(VERSION_FULL) 37 | @echo Package: $(VERSION_FULL).tar.gz 38 | @rm -rf $(VERSION_FULL) 39 | 40 | distclean: 41 | rm -rf $(BUILD) 42 | 43 | .PHONY : configured 44 | configured: 45 | @test -d $(BUILD) || ( echo "Error: No build/ directory found. Did you run configure?" && exit 1 ) 46 | @test -e $(BUILD)/Makefile || ( echo "Error: No build/Makefile found. Did you run configure?" && exit 1 ) 47 | -------------------------------------------------------------------------------- /patches/binpac-5.patch: -------------------------------------------------------------------------------- 1 | diff -urN bro-1.2.1-orig/src/pac_paramtype.cc bro-1.2.1-ssl-binpac/src/pac_paramtype.cc 2 | --- bro-1.2.1-orig/src/pac_paramtype.cc 2006-07-26 15:02:40.000000000 -0700 3 | +++ bro-1.2.1-ssl-binpac/src/pac_paramtype.cc 2007-05-10 15:09:47.470104000 -0700 4 | @@ -208,7 +208,13 @@ 5 | const char *parse_func; 6 | string parse_params; 7 | 8 | - if ( ref_type->incremental_input() ) 9 | + if ( buffer_mode() == BUFFER_NOTHING ) 10 | + { 11 | + ASSERT(!ref_type->incremental_input()); 12 | + parse_func = kParseFuncWithoutBuffer; 13 | + parse_params = "0, 0"; 14 | + } 15 | + else if ( ref_type->incremental_input() ) 16 | { 17 | parse_func = kParseFuncWithBuffer; 18 | parse_params = env->RValue(flow_buffer_id); 19 | @@ -239,15 +245,24 @@ 20 | 21 | if ( incremental_input() ) 22 | { 23 | - ASSERT(parsing_complete_var()); 24 | - out_cc->println("%s = %s;", 25 | - env->LValue(parsing_complete_var()), 26 | - call_parse_func.c_str()); 27 | - 28 | - // parsing_complete_var might have been already 29 | - // evaluated when set to false 30 | - if ( ! env->Evaluated(parsing_complete_var()) ) 31 | - env->SetEvaluated(parsing_complete_var()); 32 | + if ( buffer_mode() == BUFFER_NOTHING ) 33 | + { 34 | + out_cc->println("%s;", call_parse_func.c_str()); 35 | + out_cc->println("%s = true;", 36 | + env->LValue(parsing_complete_var())); 37 | + } 38 | + else 39 | + { 40 | + ASSERT(parsing_complete_var()); 41 | + out_cc->println("%s = %s;", 42 | + env->LValue(parsing_complete_var()), 43 | + call_parse_func.c_str()); 44 | + 45 | + // parsing_complete_var might have been already 46 | + // evaluated when set to false 47 | + if ( ! env->Evaluated(parsing_complete_var()) ) 48 | + env->SetEvaluated(parsing_complete_var()); 49 | + } 50 | } 51 | else 52 | { 53 | diff -urN bro-1.2.1-orig/src/pac_type.cc bro-1.2.1-ssl-binpac/src/pac_type.cc 54 | --- bro-1.2.1-orig/src/pac_type.cc 2006-07-26 15:02:40.000000000 -0700 55 | +++ bro-1.2.1-ssl-binpac/src/pac_type.cc 2007-05-24 10:56:42.140658000 -0700 56 | @@ -501,8 +501,8 @@ 57 | 58 | if ( buffer_mode() == BUFFER_NOTHING ) 59 | { 60 | - out_cc->println("%s = true;", 61 | - env->LValue(parsing_complete_var())); 62 | + // this is the empty type 63 | + DoGenParseCode(out_cc, env, data, flags); 64 | } 65 | else if ( buffer_input() ) 66 | { 67 | -------------------------------------------------------------------------------- /src/pac_exttype.cc: -------------------------------------------------------------------------------- 1 | #include "pac_exttype.h" 2 | 3 | #include "pac_decl.h" 4 | #include "pac_id.h" 5 | #include "pac_output.h" 6 | 7 | bool ExternType::DefineValueVar() const { return true; } 8 | 9 | string ExternType::DataTypeStr() const { 10 | switch ( ext_type_ ) { 11 | case PLAIN: 12 | case NUMBER: 13 | case BOOLEAN: return id_->Name(); 14 | case POINTER: return string(id_->Name()) + " *"; 15 | default: ASSERT(0); return ""; 16 | } 17 | } 18 | 19 | int ExternType::StaticSize(Env* env) const { 20 | ASSERT(0); 21 | return -1; 22 | } 23 | 24 | bool ExternType::ByteOrderSensitive() const { return false; } 25 | 26 | string ExternType::EvalMember(const ID* member_id) const { 27 | return strfmt("%s%s", ext_type_ == POINTER ? "->" : ".", member_id->Name()); 28 | } 29 | 30 | void ExternType::GenInitCode(Output* out_cc, Env* env) { 31 | if ( IsNumericType() ) 32 | out_cc->println("%s = 0;", env->LValue(value_var())); 33 | else if ( IsPointerType() ) 34 | out_cc->println("%s = nullptr;", env->LValue(value_var())); 35 | else if ( IsBooleanType() ) 36 | out_cc->println("%s = false;", env->LValue(value_var())); 37 | 38 | Type::GenInitCode(out_cc, env); 39 | } 40 | 41 | void ExternType::DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) { ASSERT(0); } 42 | 43 | void ExternType::GenDynamicSize(Output* out, Env* env, const DataPtr& data) { ASSERT(0); } 44 | 45 | Type* ExternType::DoClone() const { return new ExternType(id_->clone(), ext_type_); } 46 | 47 | // Definitions of pre-defined external types 48 | 49 | #define EXTERNTYPE(name, ctype, exttype) ExternType* extern_type_##name = 0; 50 | #include "pac_externtype.def" 51 | #undef EXTERNTYPE 52 | 53 | void ExternType::static_init() { 54 | ID* id; 55 | // TypeDecl *decl; 56 | // decl = new TypeDecl(id, 0, extern_type_##name); 57 | 58 | #define EXTERNTYPE(name, ctype, exttype) \ 59 | id = new ID(#ctype); \ 60 | extern_type_##name = new ExternType(id, ExternType::exttype); \ 61 | Type::AddPredefinedType(#name, extern_type_##name); 62 | #include "pac_externtype.def" 63 | #undef EXTERNTYPE 64 | } 65 | -------------------------------------------------------------------------------- /src/pac_exception.cc: -------------------------------------------------------------------------------- 1 | #include "pac_exception.h" 2 | 3 | #include "pac_expr.h" 4 | #include "pac_id.h" 5 | #include "pac_utils.h" 6 | 7 | Exception::Exception(const Object* o, string msg) { 8 | if ( o ) { 9 | msg_ = o->Location(); 10 | msg_ += ": error : "; 11 | } 12 | 13 | msg_ += msg; 14 | 15 | if ( FLAGS_pac_debug ) { 16 | DEBUG_MSG("Exception: %s\n", msg_.c_str()); 17 | abort(); 18 | } 19 | } 20 | 21 | ExceptionIDNotFound::ExceptionIDNotFound(const ID* id) : Exception(id), id_(id) { 22 | append(strfmt("`%s' undeclared", id_->Name())); 23 | } 24 | 25 | ExceptionIDRedefinition::ExceptionIDRedefinition(const ID* id) : Exception(id), id_(id) { 26 | append(strfmt("`%s' redefined", id_->Name())); 27 | } 28 | 29 | ExceptionIDNotEvaluated::ExceptionIDNotEvaluated(const ID* id) : Exception(id), id_(id) { 30 | append(strfmt("ID `%s' not evaluated before used", id->Name())); 31 | } 32 | 33 | ExceptionIDNotField::ExceptionIDNotField(const ID* id) : Exception(id), id_(id) { 34 | append(strfmt("ID `%s' is not a field", id_->Name())); 35 | } 36 | 37 | ExceptionMemberNotFound::ExceptionMemberNotFound(const ID* type_id, const ID* member_id) 38 | : Exception(member_id), type_id_(type_id), member_id_(member_id) { 39 | append(strfmt("type %s does not have member `%s'", type_id_->Name(), member_id_->Name())); 40 | } 41 | 42 | ExceptionCyclicDependence::ExceptionCyclicDependence(const ID* id) : Exception(id), id_(id) { 43 | append(strfmt("cyclic dependence through `%s'", id_->Name())); 44 | } 45 | 46 | ExceptionPaddingError::ExceptionPaddingError(const Object* o, string msg) : Exception(o) { append(msg.c_str()); } 47 | 48 | ExceptionNonConstExpr::ExceptionNonConstExpr(const Expr* expr) : Exception(expr), expr(expr) { 49 | append(strfmt("Expression `%s' is not constant", expr->orig())); 50 | } 51 | 52 | ExceptionInvalidCaseSizeExpr::ExceptionInvalidCaseSizeExpr(const Expr* expr) : Exception(expr), expr(expr) { 53 | append(strfmt("Expression `%s' is greater than the 32-bit limit for use as a case index", expr->orig())); 54 | } 55 | 56 | ExceptionInvalidCaseLimitExpr::ExceptionInvalidCaseLimitExpr(const Expr* expr) : Exception(expr), expr(expr) { 57 | append( 58 | strfmt("Expression `%s' as a case index is outside the numeric limit of the type used " 59 | "for the switch expression", 60 | expr->orig())); 61 | } 62 | -------------------------------------------------------------------------------- /src/pac_decl.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_decl_h 2 | #define pac_decl_h 3 | 4 | #include "pac_common.h" 5 | #include "pac_id.h" 6 | 7 | class Decl : public Object { 8 | public: 9 | // Note: ANALYZER is not for AnalyzerDecl (which is an 10 | // abstract class) , but for AnalyzerContextDecl. 11 | enum DeclType { ENUM, LET, TYPE, FUNC, CONN, FLOW, ANALYZER, HELPER, REGEX }; 12 | 13 | Decl(ID* id, DeclType decl_type); 14 | virtual ~Decl(); 15 | 16 | const ID* id() const { return id_; } 17 | DeclType decl_type() const { return decl_type_; } 18 | AnalyzerContextDecl* analyzer_context() const { return analyzer_context_; } 19 | 20 | // NULL except for TypeDecl or AnalyzerDecl 21 | virtual Env* env() const { return nullptr; } 22 | 23 | virtual void Prepare() = 0; 24 | 25 | // Generate declarations out of the "binpac" namespace 26 | virtual void GenExternDeclaration(Output* out_h) { /* do nothing */ 27 | } 28 | 29 | // Generate declarations before definition of classes 30 | virtual void GenForwardDeclaration(Output* out_h) = 0; 31 | 32 | virtual void GenCode(Output* out_h, Output* out_cc) = 0; 33 | 34 | void TakeExprList(); 35 | void AddAttrs(AttrList* attrlist); 36 | void SetAnalyzerContext(); 37 | 38 | protected: 39 | virtual void ProcessAttr(Attr* a); 40 | 41 | ID* id_; 42 | DeclType decl_type_; 43 | AttrList* attrlist_; 44 | AnalyzerContextDecl* analyzer_context_; 45 | 46 | public: 47 | static void ProcessDecls(Output* out_h, Output* out_cc); 48 | static Decl* LookUpDecl(const ID* id); 49 | 50 | private: 51 | static DeclList* decl_list_; 52 | typedef map DeclMap; 53 | static DeclMap decl_map_; 54 | }; 55 | 56 | class HelperDecl : public Decl { 57 | public: 58 | enum HelperType { 59 | HEADER, 60 | CODE, 61 | EXTERN, 62 | }; 63 | HelperDecl(HelperType type, ID* context_id, EmbeddedCode* code); 64 | ~HelperDecl() override; 65 | 66 | void Prepare() override; 67 | void GenExternDeclaration(Output* out_h) override; 68 | void GenForwardDeclaration(Output* out_h) override { /* do nothing */ 69 | } 70 | void GenCode(Output* out_h, Output* out_cc) override; 71 | 72 | private: 73 | HelperType helper_type_; 74 | ID* context_id_; 75 | EmbeddedCode* code_; 76 | 77 | static int helper_id_seq; 78 | }; 79 | 80 | #endif // pac_decl_h 81 | -------------------------------------------------------------------------------- /src/pac_exception.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_exception_h 2 | #define pac_exception_h 3 | 4 | #include 5 | using namespace std; 6 | 7 | #include "pac_common.h" 8 | 9 | class Exception { 10 | public: 11 | Exception(const Object* o, string msg = ""); 12 | 13 | const char* msg() const { return msg_.c_str(); } 14 | void append(string s) { msg_ += s; } 15 | 16 | private: 17 | string msg_; 18 | }; 19 | 20 | class ExceptionIDNotFound : public Exception { 21 | public: 22 | ExceptionIDNotFound(const ID* id); 23 | const ID* id() const { return id_; } 24 | 25 | private: 26 | const ID* id_; 27 | }; 28 | 29 | class ExceptionIDRedefinition : public Exception { 30 | public: 31 | ExceptionIDRedefinition(const ID* id); 32 | const ID* id() const { return id_; } 33 | 34 | private: 35 | const ID* id_; 36 | }; 37 | 38 | class ExceptionIDNotEvaluated : public Exception { 39 | public: 40 | ExceptionIDNotEvaluated(const ID* id); 41 | const ID* id() const { return id_; } 42 | 43 | private: 44 | const ID* id_; 45 | }; 46 | 47 | class ExceptionCyclicDependence : public Exception { 48 | public: 49 | ExceptionCyclicDependence(const ID* id); 50 | const ID* id() const { return id_; } 51 | 52 | private: 53 | const ID* id_; 54 | }; 55 | 56 | class ExceptionPaddingError : public Exception { 57 | public: 58 | ExceptionPaddingError(const Object* o, string msg); 59 | }; 60 | 61 | class ExceptionIDNotField : public Exception { 62 | public: 63 | ExceptionIDNotField(const ID* id); 64 | const ID* id() const { return id_; } 65 | 66 | private: 67 | const ID* id_; 68 | }; 69 | 70 | class ExceptionMemberNotFound : public Exception { 71 | public: 72 | ExceptionMemberNotFound(const ID* type_id, const ID* member_id); 73 | 74 | private: 75 | const ID *type_id_, *member_id_; 76 | }; 77 | 78 | class ExceptionNonConstExpr : public Exception { 79 | public: 80 | ExceptionNonConstExpr(const Expr* expr); 81 | 82 | private: 83 | const Expr* expr; 84 | }; 85 | 86 | class ExceptionInvalidCaseSizeExpr : public Exception { 87 | public: 88 | ExceptionInvalidCaseSizeExpr(const Expr* expr); 89 | 90 | private: 91 | const Expr* expr; 92 | }; 93 | 94 | class ExceptionInvalidCaseLimitExpr : public Exception { 95 | public: 96 | ExceptionInvalidCaseLimitExpr(const Expr* expr); 97 | 98 | private: 99 | const Expr* expr; 100 | }; 101 | 102 | #endif /* pac_exception_h */ 103 | -------------------------------------------------------------------------------- /.cmake-format.json: -------------------------------------------------------------------------------- 1 | { 2 | "parse": { 3 | "additional_commands": { 4 | "CheckIPProto": { 5 | "kwargs": { 6 | "_proto": "*" 7 | } 8 | }, 9 | "CheckType": { 10 | "kwargs": { 11 | "_type": "*", 12 | "_alt_type": "*", 13 | "_var": "*" 14 | } 15 | }, 16 | "SetPackageVersion": { 17 | "kwargs": { 18 | "_version": "*" 19 | } 20 | }, 21 | "SetPackageFileName": { 22 | "kwargs": { 23 | "_version": "*" 24 | } 25 | }, 26 | "SetPackageInstallScripts": { 27 | "kwargs": { 28 | "VERSION": "*" 29 | } 30 | }, 31 | "ConfigurePackaging": { 32 | "kwargs": { 33 | "_version": "*" 34 | } 35 | }, 36 | "SetPackageGenerators": {}, 37 | "SetPackageMetadata": {}, 38 | "FindRequiredPackage": { 39 | "kwargs": { 40 | "packageName": "*" 41 | } 42 | }, 43 | "InstallClobberImmune": { 44 | "kwargs": { 45 | "_srcfile": "*", 46 | "_dstfile": "*" 47 | } 48 | }, 49 | "InstallPackageConfigFile": { 50 | "kwargs": { 51 | "_srcfile": "*", 52 | "_dstdir": "*", 53 | "_dstfilename": "*" 54 | } 55 | }, 56 | "InstallShellScript": { 57 | "kwargs": { 58 | "_srcfile": "*", 59 | "_dstfile": "*" 60 | } 61 | }, 62 | "InstallSymLink": { 63 | "kwargs": { 64 | "_filepath": "*", 65 | "_sympath": "*" 66 | } 67 | }, 68 | "spicy_add_analyzer": { 69 | "kwargs": { 70 | "NAME": "*", 71 | "PACKAGE_NAME": "*", 72 | "SOURCES": "*", 73 | "MODULES": "*" 74 | } 75 | }, 76 | "zeek_add_plugin": { 77 | "kwargs": { 78 | "INCLUDE_DIRS": "*", 79 | "DEPENDENCIES": "*", 80 | "SOURCES": "*", 81 | "BIFS": "*", 82 | "PAC": "*" 83 | } 84 | } 85 | } 86 | }, 87 | "format": { 88 | "always_wrap": [ 89 | "spicy_add_analyzer", 90 | "zeek_add_plugin" 91 | ], 92 | "line_width": 100, 93 | "tab_size": 4, 94 | "separate_ctrl_name_with_space": true, 95 | "max_subgroups_hwrap": 3, 96 | "line_ending": "unix" 97 | }, 98 | "markup": { 99 | "enable_markup": false 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/pac_strtype.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_strtype_h 2 | #define pac_strtype_h 3 | 4 | #include "pac_type.h" 5 | 6 | // TODO: question: shall we merge it with ArrayType? 7 | class StringType : public Type { 8 | public: 9 | enum StringTypeEnum { CSTR, REGEX, ANYSTR }; 10 | 11 | explicit StringType(StringTypeEnum anystr); 12 | explicit StringType(ConstString* str); 13 | explicit StringType(RegEx* regex); 14 | ~StringType() override; 15 | 16 | bool DefineValueVar() const override; 17 | string DataTypeStr() const override; 18 | string DefaultValue() const override { return "0"; } 19 | Type* ElementDataType() const override; 20 | 21 | void Prepare(Env* env, int flags) override; 22 | 23 | void GenPubDecls(Output* out, Env* env) override; 24 | void GenPrivDecls(Output* out, Env* env) override; 25 | 26 | void GenInitCode(Output* out, Env* env) override; 27 | void GenCleanUpCode(Output* out, Env* env) override; 28 | 29 | void DoMarkIncrementalInput() override; 30 | 31 | int StaticSize(Env* env) const override; 32 | 33 | bool IsPointerType() const override { return false; } 34 | 35 | void ProcessAttr(Attr* a) override; 36 | 37 | protected: 38 | void init(); 39 | 40 | // Generate computation of size of the string and returns the string 41 | // representing a constant integer or name of the length variable. 42 | string GenStringSize(Output* out_cc, Env* env, const DataPtr& data); 43 | 44 | // Generate a string mismatch exception 45 | void GenStringMismatch(Output* out_cc, Env* env, const DataPtr& data, string pattern); 46 | 47 | void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; 48 | 49 | void GenCheckingCStr(Output* out, Env* env, const DataPtr& data, const string& str_size); 50 | 51 | void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; 52 | void GenDynamicSizeAnyStr(Output* out_cc, Env* env, const DataPtr& data); 53 | void GenDynamicSizeRegEx(Output* out_cc, Env* env, const DataPtr& data); 54 | 55 | Type* DoClone() const override; 56 | 57 | // TODO: insensitive towards byte order till we support unicode 58 | bool ByteOrderSensitive() const override { return false; } 59 | 60 | protected: 61 | bool DoTraverse(DataDepVisitor* visitor) override; 62 | 63 | private: 64 | const ID* string_length_var() const; 65 | 66 | StringTypeEnum type_; 67 | ConstString* str_; 68 | RegEx* regex_; 69 | Field* string_length_var_field_; 70 | Type* elem_datatype_; 71 | 72 | public: 73 | static void static_init(); 74 | 75 | private: 76 | static const char* kStringTypeName; 77 | static const char* kConstStringTypeName; 78 | }; 79 | 80 | #endif // pac_strtype_h 81 | -------------------------------------------------------------------------------- /src/pac_func.cc: -------------------------------------------------------------------------------- 1 | #include "pac_func.h" 2 | 3 | #include "pac_embedded.h" 4 | #include "pac_expr.h" 5 | #include "pac_output.h" 6 | #include "pac_param.h" 7 | #include "pac_type.h" 8 | 9 | Function::Function(ID* id, Type* type, ParamList* params) 10 | : id_(id), type_(type), params_(params), expr_(nullptr), code_(nullptr) { 11 | analyzer_decl_ = nullptr; 12 | env_ = nullptr; 13 | } 14 | 15 | Function::~Function() { 16 | delete id_; 17 | delete type_; 18 | delete_list(ParamList, params_); 19 | delete env_; 20 | delete expr_; 21 | delete code_; 22 | } 23 | 24 | void Function::Prepare(Env* env) { 25 | env->AddID(id_, FUNC_ID, type_); 26 | env->SetEvaluated(id_); 27 | 28 | env_ = new Env(env, this); 29 | 30 | foreach (i, ParamList, params_) { 31 | Param* p = *i; 32 | env_->AddID(p->id(), FUNC_PARAM, p->type()); 33 | env_->SetEvaluated(p->id()); 34 | } 35 | } 36 | 37 | void Function::GenForwardDeclaration(Output* out_h) { 38 | // Do nothing 39 | } 40 | 41 | void Function::GenCode(Output* out_h, Output* out_cc) { 42 | out_h->println("%s %s(%s);", type_->DataTypeStr().c_str(), id_->Name(), ParamDecls(params_).c_str()); 43 | 44 | string class_str = ""; 45 | if ( analyzer_decl_ ) 46 | class_str = strfmt("%s::", analyzer_decl_->id()->Name()); 47 | 48 | string proto_str = strfmt("%s %s%s(%s)", type_->DataTypeStr().c_str(), class_str.c_str(), id_->Name(), 49 | ParamDecls(params_).c_str()); 50 | 51 | ASSERT(! (expr_ && code_)); 52 | 53 | if ( expr_ ) { 54 | out_cc->println("%s {", proto_str.c_str()); 55 | out_cc->inc_indent(); 56 | 57 | out_cc->println("return static_cast<%s>(%s);", type_->DataTypeStr().c_str(), expr_->EvalExpr(out_cc, env_)); 58 | 59 | out_cc->dec_indent(); 60 | out_cc->println("}"); 61 | } 62 | 63 | else if ( code_ ) { 64 | out_cc->println("%s {", proto_str.c_str()); 65 | out_cc->inc_indent(); 66 | 67 | code_->GenCode(out_cc, env_); 68 | 69 | out_cc->dec_indent(); 70 | out_cc->println("}"); 71 | } 72 | 73 | out_cc->println(""); 74 | } 75 | 76 | FuncDecl::FuncDecl(Function* function) : Decl(function->id()->clone(), FUNC), function_(function) { 77 | function_->Prepare(global_env()); 78 | } 79 | 80 | FuncDecl::~FuncDecl() { delete function_; } 81 | 82 | void FuncDecl::Prepare() {} 83 | 84 | void FuncDecl::GenForwardDeclaration(Output* out_h) { function_->GenForwardDeclaration(out_h); } 85 | 86 | void FuncDecl::GenCode(Output* out_h, Output* out_cc) { function_->GenCode(out_h, out_cc); } 87 | 88 | AnalyzerFunction::AnalyzerFunction(Function* function) : AnalyzerElement(FUNCTION), function_(function) {} 89 | -------------------------------------------------------------------------------- /src/pac_action.cc: -------------------------------------------------------------------------------- 1 | #include "pac_action.h" 2 | 3 | #include "pac_embedded.h" 4 | #include "pac_exception.h" 5 | #include "pac_id.h" 6 | #include "pac_output.h" 7 | #include "pac_type.h" 8 | #include "pac_typedecl.h" 9 | #include "pac_utils.h" 10 | 11 | AnalyzerAction::AnalyzerAction(ID* action_id, When when, ActionParam* param, EmbeddedCode* code) 12 | : AnalyzerElement(ACTION), action_id_(action_id), when_(when), param_(param), code_(code), analyzer_(nullptr) {} 13 | 14 | AnalyzerAction::~AnalyzerAction() { 15 | delete action_id_; 16 | delete param_; 17 | delete code_; 18 | } 19 | 20 | string AnalyzerAction::action_function() const { return strfmt("Action_%s", action_id_->Name()); } 21 | 22 | void AnalyzerAction::InstallHook(AnalyzerDecl* analyzer) { 23 | ASSERT(0); 24 | analyzer_ = analyzer; 25 | // param_->MainDataType()->InstallAction(this); 26 | } 27 | 28 | void AnalyzerAction::GenCode(Output* out_h, Output* out_cc, AnalyzerDecl* decl) { 29 | Env action_func_env(decl->env(), this); 30 | action_func_env.AddID(param_->id(), TEMP_VAR, param_->DataType()); 31 | action_func_env.SetEvaluated(param_->id()); 32 | 33 | string action_func_proto = strfmt("%s(%s)", action_function().c_str(), ParamDecls(&action_func_env).c_str()); 34 | 35 | out_h->println("void %s;", action_func_proto.c_str()); 36 | 37 | out_cc->println("void %s::%s {", decl->class_name().c_str(), action_func_proto.c_str()); 38 | out_cc->inc_indent(); 39 | 40 | code_->GenCode(out_cc, &action_func_env); 41 | 42 | out_cc->println(""); 43 | out_cc->dec_indent(); 44 | out_cc->println("}"); 45 | out_cc->println(""); 46 | } 47 | 48 | string AnalyzerAction::ParamDecls(Env* env) const { return param_->DeclStr(env); } 49 | 50 | Type* ActionParam::MainDataType() const { 51 | // Note: this is not equal to DataType() 52 | Type* main_type = TypeDecl::LookUpType(type()->type_id()); 53 | 54 | if ( ! main_type ) { 55 | throw Exception(type()->type_id(), "type not defined"); 56 | } 57 | 58 | return main_type; 59 | } 60 | 61 | Type* ActionParam::DataType() const { 62 | Type* main_type = MainDataType(); 63 | 64 | if ( ! type()->field_id() ) { 65 | return main_type; 66 | } 67 | else { 68 | Type* member_type = main_type->MemberDataType(type()->field_id()); 69 | if ( ! member_type ) { 70 | throw Exception(type()->field_id(), strfmt("cannot find member type for `%s.%s'", type()->type_id()->Name(), 71 | type()->field_id()->Name())); 72 | } 73 | return member_type; 74 | } 75 | } 76 | 77 | string ActionParam::DeclStr(Env* env) const { 78 | return strfmt("%s %s", DataType()->DataTypeStr().c_str(), env->LValue(id())); 79 | } 80 | -------------------------------------------------------------------------------- /src/pac_array.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_array_h 2 | #define pac_array_h 3 | 4 | #include "pac_common.h" 5 | #include "pac_type.h" 6 | 7 | // Fixed-length array and variable length sequence with an ending pattern 8 | 9 | class ArrayType : public Type { 10 | public: 11 | ArrayType(Type* arg_elemtype, Expr* arg_length = nullptr); 12 | ~ArrayType() override; 13 | 14 | bool DefineValueVar() const override; 15 | string DataTypeStr() const override; 16 | string DefaultValue() const override { return "0"; } 17 | Type* ElementDataType() const override; 18 | 19 | string EvalElement(const string& array, const string& index) const override; 20 | 21 | void ProcessAttr(Attr* a) override; 22 | 23 | void Prepare(Env* env, int flags) override; 24 | 25 | void GenPubDecls(Output* out, Env* env) override; 26 | void GenPrivDecls(Output* out, Env* env) override; 27 | 28 | void GenInitCode(Output* out, Env* env) override; 29 | void GenCleanUpCode(Output* out, Env* env) override; 30 | 31 | int StaticSize(Env* env) const override; 32 | 33 | void SetBoundaryChecked() override; 34 | void GenUntilInputCheck(Output* out_cc, Env* env); 35 | 36 | bool IsPointerType() const override { return true; } 37 | 38 | protected: 39 | void init(); 40 | 41 | void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; 42 | void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; 43 | void GenArrayLength(Output* out_cc, Env* env, const DataPtr& data); 44 | string GenArrayInit(Output* out_cc, Env* env, bool known_array_length); 45 | void GenElementAssignment(Output* out_cc, Env* env, string const& array_str, bool use_vector); 46 | void GenUntilCheck(Output* out_cc, Env* env, Expr* until_condition, bool delete_elem); 47 | 48 | bool ByteOrderSensitive() const override { return elemtype_->RequiresByteOrder(); } 49 | bool RequiresAnalyzerContext() override; 50 | 51 | Type* DoClone() const override; 52 | 53 | void DoMarkIncrementalInput() override; 54 | 55 | const ID* arraylength_var() const; 56 | const ID* elem_it_var() const; 57 | const ID* elem_var() const; 58 | const ID* elem_dataptr_var() const; 59 | const ID* elem_input_var() const; 60 | 61 | protected: 62 | bool DoTraverse(DataDepVisitor* visitor) override; 63 | 64 | private: 65 | Type* elemtype_; 66 | Expr* length_; 67 | 68 | string vector_str_; 69 | string datatype_str_; 70 | string end_of_array_loop_label_; 71 | 72 | Field* arraylength_var_field_; 73 | Field* elem_it_var_field_; 74 | Field* elem_var_field_; 75 | Field* elem_dataptr_var_field_; 76 | Field* elem_input_var_field_; 77 | 78 | // This does not come from &until, but is internally generated 79 | Expr* elem_dataptr_until_expr_; 80 | 81 | Expr* attr_generic_until_expr_; 82 | Expr* attr_until_element_expr_; 83 | Expr* attr_until_input_expr_; 84 | }; 85 | 86 | #endif // pac_array_h 87 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15.0 FATAL_ERROR) 2 | project(BinPAC C CXX) 3 | include(cmake/CommonCMakeConfig.cmake) 4 | include(cmake/RequireCXXStd.cmake) 5 | 6 | file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" BINPAC_VERSION LIMIT_COUNT 1) 7 | string(REPLACE "." " " _version_numbers ${BINPAC_VERSION}) 8 | separate_arguments(_version_numbers) 9 | list(GET _version_numbers 0 BINPAC_VERSION_MAJOR) 10 | list(GET _version_numbers 1 BINPAC_VERSION_MINOR) 11 | string(REGEX REPLACE "-[0-9]*$" "" BINPAC_VERSION_MINOR ${BINPAC_VERSION_MINOR}) 12 | 13 | # The SO number shall increase only if binary interface changes. 14 | set(BINPAC_SOVERSION 0) 15 | 16 | set(ENABLE_SHARED true) 17 | 18 | if (ENABLE_STATIC_ONLY) 19 | set(ENABLE_STATIC true) 20 | set(ENABLE_SHARED false) 21 | endif () 22 | 23 | # Set default install paths 24 | include(GNUInstallDirs) 25 | 26 | # ############################################################################## 27 | # Dependency Configuration 28 | 29 | find_package(FLEX REQUIRED) 30 | find_package(BISON REQUIRED) 31 | 32 | if (MSVC) 33 | add_compile_options(/J) # Similar to -funsigned-char on other platforms 34 | endif () 35 | 36 | # ############################################################################## 37 | # System Introspection 38 | 39 | configure_file(${PROJECT_SOURCE_DIR}/config.h.in ${PROJECT_BINARY_DIR}/config.h) 40 | 41 | include_directories(BEFORE ${PROJECT_BINARY_DIR}) 42 | 43 | # ############################################################################## 44 | # Recurse on sub-directories 45 | 46 | add_subdirectory(lib) 47 | add_subdirectory(src) 48 | 49 | # ############################################################################## 50 | # Build Summary 51 | 52 | if (CMAKE_BUILD_TYPE) 53 | string(TOUPPER ${CMAKE_BUILD_TYPE} BuildType) 54 | endif () 55 | 56 | macro (display test desc summary) 57 | if (${test}) 58 | set(${summary} ${desc}) 59 | else () 60 | set(${summary} no) 61 | endif () 62 | endmacro () 63 | 64 | display(ENABLE_SHARED yes shared_summary) 65 | display(ENABLE_STATIC yes static_summary) 66 | 67 | message( 68 | "\n==================| BinPAC Build Summary |====================" 69 | "\nVersion: ${BINPAC_VERSION}" 70 | "\nSO version: ${BINPAC_SOVERSION}" 71 | "\n" 72 | "\nBuild Type: ${CMAKE_BUILD_TYPE}" 73 | "\nDebug mode: ${ENABLE_DEBUG}" 74 | "\nInstall prefix: ${CMAKE_INSTALL_PREFIX}" 75 | "\nShared libs: ${shared_summary}" 76 | "\nStatic libs: ${static_summary}" 77 | "\n" 78 | "\nCC: ${CMAKE_C_COMPILER}" 79 | "\nCFLAGS: ${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${BuildType}}" 80 | "\nCXX: ${CMAKE_CXX_COMPILER}" 81 | "\nCXXFLAGS: ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BuildType}}" 82 | "\nCPP: ${CMAKE_CXX_COMPILER}" 83 | "\n" 84 | "\n================================================================\n") 85 | 86 | include(UserChangedWarning) 87 | -------------------------------------------------------------------------------- /src/pac_context.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_context_h 2 | #define pac_context_h 3 | 4 | #include "pac_common.h" 5 | #include "pac_field.h" 6 | #include "pac_type.h" 7 | #include "pac_typedecl.h" 8 | 9 | // AnalyzerContext represents a cookie that an analyzer gives to 10 | // parse functions of various message types. The cookie is parsed 11 | // to every parse function (if necessary) as parameter 'binpac_context'. 12 | // 13 | // The members of the cookie is declared through 'analyzer' declarations, 14 | // such as in: 15 | // 16 | // analyzer SunRPC withcontext { 17 | // connection: RPC_Conn; 18 | // flow: RPC_Flow; 19 | // }; 20 | // 21 | // The cookie usually contains the connection and flow in which 22 | // the message appears, and the context information can be 23 | // accessed as members of the cookie, such as 24 | // ``binpac_context.connection''. 25 | 26 | class ContextField : public Field { 27 | public: 28 | ContextField(ID* id, Type* type); 29 | }; 30 | 31 | class AnalyzerContextDecl : public TypeDecl { 32 | public: 33 | AnalyzerContextDecl(ID* id, ContextFieldList* context_fields); 34 | ~AnalyzerContextDecl() override; 35 | 36 | void AddFlowBuffer(); 37 | 38 | const ID* context_name_id() const { return context_name_id_; } 39 | 40 | // The type of analyzer context as a parameter 41 | ParameterizedType* param_type() const { return param_type_; } 42 | 43 | void GenForwardDeclaration(Output* out_h) override; 44 | void GenCode(Output* out_h, Output* out_cc) override; 45 | 46 | void GenNamespaceBegin(Output* out) const; 47 | void GenNamespaceEnd(Output* out) const; 48 | 49 | private: 50 | ID* context_name_id_; 51 | ContextFieldList* context_fields_; 52 | ParameterizedType* param_type_; 53 | bool flow_buffer_added_; 54 | 55 | // static members 56 | public: 57 | static AnalyzerContextDecl* current_analyzer_context() { return current_analyzer_context_; } 58 | 59 | static string mb_buffer(Env* env); 60 | 61 | private: 62 | static AnalyzerContextDecl* current_analyzer_context_; 63 | }; 64 | 65 | class DummyType : public Type { 66 | public: 67 | DummyType() : Type(DUMMY) {} 68 | 69 | bool DefineValueVar() const override { return false; } 70 | string DataTypeStr() const override { 71 | ASSERT(0); 72 | return ""; 73 | } 74 | 75 | int StaticSize(Env* env) const override { 76 | ASSERT(0); 77 | return -1; 78 | } 79 | 80 | bool ByteOrderSensitive() const override { return false; } 81 | 82 | bool IsPointerType() const override { 83 | ASSERT(0); 84 | return false; 85 | } 86 | 87 | void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override { ASSERT(0); } 88 | 89 | // Generate code for computing the dynamic size of the type 90 | void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override { ASSERT(0); } 91 | 92 | protected: 93 | Type* DoClone() const override; 94 | void DoMarkIncrementalInput() override { ASSERT(0); } 95 | }; 96 | 97 | #endif // pac_context_h 98 | -------------------------------------------------------------------------------- /lib/binpac_exception.h: -------------------------------------------------------------------------------- 1 | #ifndef binpac_exception_h 2 | #define binpac_exception_h 3 | 4 | #include 5 | #include 6 | 7 | namespace binpac { 8 | 9 | class Exception { 10 | public: 11 | Exception(const char* m = 0) : msg_("binpac exception: ") { 12 | if ( m ) 13 | append(m); 14 | // abort(); 15 | } 16 | 17 | void append(string m) { msg_ += m; } 18 | string msg() const { return msg_; } 19 | const char* c_msg() const { return msg_.c_str(); } 20 | 21 | protected: 22 | string msg_; 23 | }; 24 | 25 | class ExceptionEnforceViolation : public Exception { 26 | public: 27 | ExceptionEnforceViolation(const char* where) { append(binpac_fmt("&enforce violation : %s", where)); } 28 | }; 29 | 30 | class ExceptionOutOfBound : public Exception { 31 | public: 32 | ExceptionOutOfBound(const char* where, int len_needed, int len_given) { 33 | append(binpac_fmt("out_of_bound: %s: %d > %d", where, len_needed, len_given)); 34 | } 35 | }; 36 | 37 | class ExceptionInvalidCase : public Exception { 38 | public: 39 | ExceptionInvalidCase(const char* location, int64_t index, const char* expected) 40 | : location_(location), index_(index), expected_(expected) { 41 | append(binpac_fmt("invalid case: %s: %" PRIi64 " (%s)", location, index, expected)); 42 | } 43 | 44 | protected: 45 | const char* location_; 46 | int64_t index_; 47 | string expected_; 48 | }; 49 | 50 | class ExceptionInvalidCaseIndex : public Exception { 51 | public: 52 | ExceptionInvalidCaseIndex(const char* location, int64_t index) : location_(location), index_(index) { 53 | append(binpac_fmt("invalid index for case: %s: %" PRIi64, location, index)); 54 | } 55 | 56 | protected: 57 | const char* location_; 58 | int64_t index_; 59 | }; 60 | 61 | class ExceptionInvalidOffset : public Exception { 62 | public: 63 | ExceptionInvalidOffset(const char* location, int min_offset, int offset) 64 | : location_(location), min_offset_(min_offset), offset_(offset) { 65 | append(binpac_fmt("invalid offset: %s: min_offset = %d, offset = %d", location, min_offset, offset)); 66 | } 67 | 68 | protected: 69 | const char* location_; 70 | int min_offset_, offset_; 71 | }; 72 | 73 | class ExceptionStringMismatch : public Exception { 74 | public: 75 | ExceptionStringMismatch(const char* location, const char* expected, const char* actual_data) { 76 | append(binpac_fmt("string mismatch at %s: \nexpected pattern: \"%s\"\nactual data: \"%s\"", location, expected, 77 | actual_data)); 78 | } 79 | }; 80 | 81 | class ExceptionInvalidStringLength : public Exception { 82 | public: 83 | ExceptionInvalidStringLength(const char* location, int len) { 84 | append(binpac_fmt("invalid length string: %s: %d", location, len)); 85 | } 86 | }; 87 | 88 | class ExceptionFlowBufferAlloc : public Exception { 89 | public: 90 | ExceptionFlowBufferAlloc(const char* reason) { append(binpac_fmt("flowbuffer allocation failed: %s", reason)); } 91 | }; 92 | 93 | } // namespace binpac 94 | 95 | #endif // binpac_exception_h 96 | -------------------------------------------------------------------------------- /src/pac_case.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_case_h 2 | #define pac_case_h 3 | 4 | #include "pac_common.h" 5 | #include "pac_field.h" 6 | #include "pac_id.h" 7 | #include "pac_type.h" 8 | 9 | class CaseType : public Type { 10 | public: 11 | CaseType(Expr* index, CaseFieldList* cases); 12 | ~CaseType() override; 13 | 14 | void AddCaseField(CaseField* f); 15 | 16 | bool DefineValueVar() const override; 17 | string DataTypeStr() const override; 18 | string DefaultValue() const override; 19 | 20 | void Prepare(Env* env, int flags) override; 21 | 22 | void GenPubDecls(Output* out, Env* env) override; 23 | void GenPrivDecls(Output* out, Env* env) override; 24 | 25 | void GenInitCode(Output* out, Env* env) override; 26 | void GenCleanUpCode(Output* out, Env* env) override; 27 | 28 | int StaticSize(Env* env) const override; 29 | 30 | void SetBoundaryChecked() override; 31 | 32 | Type* ValueType() const; 33 | 34 | Expr* IndexExpr() const { return index_expr_; } 35 | 36 | bool IsPointerType() const override { return ValueType()->IsPointerType(); } 37 | 38 | protected: 39 | void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; 40 | void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; 41 | Type* DoClone() const override { return nullptr; } 42 | void DoMarkIncrementalInput() override; 43 | 44 | bool ByteOrderSensitive() const override; 45 | 46 | Expr* index_expr_; 47 | ID* index_var_; 48 | CaseFieldList* cases_; 49 | 50 | typedef map member_map_t; 51 | member_map_t member_map_; 52 | }; 53 | 54 | class CaseField : public Field { 55 | public: 56 | CaseField(ExprList* index, ID* id, Type* type); 57 | ~CaseField() override; 58 | 59 | CaseType* case_type() const { return case_type_; } 60 | void set_case_type(CaseType* t) { case_type_ = t; } 61 | 62 | ExprList* index() const { return index_; } 63 | 64 | const char* lvalue() const { return type_->lvalue(); } 65 | 66 | const char* CaseStr(Env* env); 67 | void set_index_var(const ID* var) { index_var_ = var; } 68 | 69 | void Prepare(Env* env) override; 70 | 71 | void GenPubDecls(Output* out, Env* env) override; 72 | 73 | void GenInitCode(Output* out, Env* env) override; 74 | void GenCleanUpCode(Output* out, Env* env) override; 75 | void GenParseCode(Output* out, Env* env, const DataPtr& data, const ID* size_var); 76 | 77 | int StaticSize(Env* env) const { return type_->StaticSize(env); } 78 | 79 | bool IsDefaultCase() const { return ! index_; } 80 | void SetBoundaryChecked() { type_->SetBoundaryChecked(); } 81 | 82 | bool RequiresByteOrder() const { return type_->RequiresByteOrder(); } 83 | bool RequiresAnalyzerContext() const override; 84 | 85 | protected: 86 | bool DoTraverse(DataDepVisitor* visitor) override; 87 | 88 | protected: 89 | CaseType* case_type_; 90 | ExprList* index_; 91 | const ID* index_var_; 92 | }; 93 | 94 | // Generate a list of "case X:" lines from index_list. Each index 95 | // expression must be constant foldable. 96 | void GenCaseStr(ExprList* index_list, Output* out_cc, Env* env, Type* switch_type); 97 | 98 | #endif // pac_case_h 99 | -------------------------------------------------------------------------------- /src/pac_context.cc: -------------------------------------------------------------------------------- 1 | #include "pac_context.h" 2 | 3 | #include "pac_analyzer.h" 4 | #include "pac_exception.h" 5 | #include "pac_exttype.h" 6 | #include "pac_flow.h" 7 | #include "pac_id.h" 8 | #include "pac_output.h" 9 | #include "pac_param.h" 10 | #include "pac_paramtype.h" 11 | #include "pac_type.h" 12 | #include "pac_utils.h" 13 | 14 | ContextField::ContextField(ID* id, Type* type) 15 | : Field(CONTEXT_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type) {} 16 | 17 | AnalyzerContextDecl* AnalyzerContextDecl::current_analyzer_context_ = nullptr; 18 | 19 | namespace { 20 | ParamList* ContextFieldsToParams(ContextFieldList* context_fields) { 21 | // Convert context fields to parameters 22 | ParamList* params = new ParamList(); 23 | foreach (i, ContextFieldList, context_fields) { 24 | ContextField* f = *i; 25 | params->push_back(new Param(f->id()->clone(), f->type())); 26 | } 27 | return params; 28 | } 29 | } // namespace 30 | 31 | AnalyzerContextDecl::AnalyzerContextDecl(ID* id, ContextFieldList* context_fields) 32 | : TypeDecl(new ID(strfmt("Context%s", id->Name())), ContextFieldsToParams(context_fields), new DummyType()) { 33 | context_name_id_ = id; 34 | if ( current_analyzer_context_ != nullptr ) { 35 | throw Exception(this, strfmt("multiple declaration of analyzer context; " 36 | "the previous one is `%s'", 37 | current_analyzer_context_->id()->Name())); 38 | } 39 | else 40 | current_analyzer_context_ = this; 41 | 42 | context_fields_ = context_fields; 43 | 44 | param_type_ = new ParameterizedType(id_->clone(), nullptr); 45 | 46 | flow_buffer_added_ = false; 47 | 48 | DEBUG_MSG("Context type: %s\n", param_type()->class_name().c_str()); 49 | } 50 | 51 | AnalyzerContextDecl::~AnalyzerContextDecl() { 52 | delete context_name_id_; 53 | delete param_type_; 54 | delete_list(ContextFieldList, context_fields_); 55 | } 56 | 57 | void AnalyzerContextDecl::GenForwardDeclaration(Output* out_h) { 58 | GenNamespaceBegin(out_h); 59 | TypeDecl::GenForwardDeclaration(out_h); 60 | } 61 | 62 | void AnalyzerContextDecl::GenCode(Output* out_h, Output* out_cc) { 63 | GenNamespaceBegin(out_h); 64 | GenNamespaceBegin(out_cc); 65 | TypeDecl::GenCode(out_h, out_cc); 66 | } 67 | 68 | void AnalyzerContextDecl::GenNamespaceBegin(Output* out) const { 69 | out->println("namespace %s {", context_name_id()->Name()); 70 | } 71 | 72 | void AnalyzerContextDecl::GenNamespaceEnd(Output* out) const { 73 | out->println("} // namespace %s", context_name_id()->Name()); 74 | } 75 | 76 | void AnalyzerContextDecl::AddFlowBuffer() { 77 | if ( flow_buffer_added_ ) 78 | return; 79 | 80 | AddParam(new Param(new ID(kFlowBufferVar), FlowDecl::flow_buffer_type()->Clone())); 81 | 82 | flow_buffer_added_ = true; 83 | } 84 | 85 | string AnalyzerContextDecl::mb_buffer(Env* env) { 86 | // A hack. The orthodox way would be to build an Expr of 87 | // context.flow_buffer_var, and then EvalExpr. 88 | return strfmt("%s->%s()", env->RValue(analyzer_context_id), kFlowBufferVar); 89 | } 90 | 91 | Type* DummyType::DoClone() const { 92 | // Fields will be copied in Type::Clone(). 93 | return new DummyType(); 94 | } 95 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | bison_target(PACParser pac_parse.yy ${BinPAC_BINARY_DIR}/src/pac_parse.cc 2 | DEFINES_FILE ${BinPAC_BINARY_DIR}/src/pac_parse.h COMPILE_FLAGS "--debug") 3 | flex_target(PACScanner pac_scan.ll ${BinPAC_BINARY_DIR}/pac_scan.cc) 4 | add_flex_bison_dependency(PACScanner PACParser) 5 | if (MSVC) 6 | set_property(SOURCE pac_scan.cc APPEND_STRING PROPERTY COMPILE_FLAGS "/wd4018") 7 | else () 8 | set_property(SOURCE pac_scan.cc APPEND_STRING PROPERTY COMPILE_FLAGS "-Wno-sign-compare") 9 | endif () 10 | 11 | include_directories(${PROJECT_SOURCE_DIR}/src ${PROJECT_BINARY_DIR}/src) 12 | 13 | set(binpac_SRCS 14 | ${BISON_PACParser_INPUT} 15 | ${FLEX_PACScanner_INPUT} 16 | ${BISON_PACParser_OUTPUTS} 17 | ${FLEX_PACScanner_OUTPUTS} 18 | pac_action.cc 19 | pac_analyzer.cc 20 | pac_array.cc 21 | pac_attr.cc 22 | pac_btype.cc 23 | pac_case.cc 24 | pac_conn.cc 25 | pac_context.cc 26 | pac_cstr.cc 27 | pac_datadep.cc 28 | pac_dataptr.cc 29 | pac_dataunit.cc 30 | pac_decl.cc 31 | pac_embedded.cc 32 | pac_enum.cc 33 | pac_expr.cc 34 | pac_exttype.cc 35 | pac_field.cc 36 | pac_flow.cc 37 | pac_func.cc 38 | pac_id.cc 39 | pac_inputbuf.cc 40 | pac_let.cc 41 | pac_param.cc 42 | pac_paramtype.cc 43 | pac_primitive.cc 44 | pac_record.cc 45 | pac_redef.cc 46 | pac_regex.cc 47 | pac_state.cc 48 | pac_strtype.cc 49 | pac_type.cc 50 | pac_typedecl.cc 51 | pac_withinput.cc 52 | pac_output.cc 53 | pac_utils.cc 54 | pac_exception.cc 55 | pac_main.cc 56 | pac_action.h 57 | pac_analyzer.h 58 | pac_array.h 59 | pac_attr.h 60 | pac_btype.h 61 | pac_case.h 62 | pac_cclass.h 63 | pac_common.h 64 | pac_conn.h 65 | pac_context.h 66 | pac_cstr.h 67 | pac_ctype.h 68 | pac_datadep.h 69 | pac_dataptr.h 70 | pac_dataunit.h 71 | pac_dbg.h 72 | pac_decl-inl.h 73 | pac_decl.h 74 | pac_embedded.h 75 | pac_enum.h 76 | pac_exception.h 77 | pac_expr.h 78 | pac_exttype.h 79 | pac_field.h 80 | pac_flow.h 81 | pac_func.h 82 | pac_id.h 83 | pac_inputbuf.h 84 | pac_let.h 85 | pac_nullptr.h 86 | pac_number.h 87 | pac_output.h 88 | pac_param.h 89 | pac_paramtype.h 90 | pac_primitive.h 91 | pac_record.h 92 | pac_redef.h 93 | pac_regex.h 94 | pac_state.h 95 | pac_strtype.h 96 | pac_type.h 97 | pac_typedecl.h 98 | pac_utils.h 99 | pac_varfield.h 100 | pac_withinput.h) 101 | 102 | include(${PROJECT_SOURCE_DIR}/cmake/RequireCXXStd.cmake) 103 | 104 | add_executable(binpac ${binpac_SRCS}) 105 | 106 | if (MSVC) 107 | # If building separately from zeek, we need to add the libunistd subdirectory 108 | # so that linking doesn't fail. 109 | if ("${CMAKE_PROJECT_NAME}" STREQUAL "BinPAC") 110 | add_subdirectory(auxil/libunistd EXCLUDE_FROM_ALL) 111 | endif () 112 | target_link_libraries(binpac PRIVATE libunistd) 113 | endif () 114 | 115 | install(TARGETS binpac DESTINATION bin) 116 | 117 | # This is set to assist superprojects that want to build BinPac from source and 118 | # rely on it as a target 119 | set(BinPAC_EXE binpac CACHE STRING "BinPAC executable" FORCE) 120 | -------------------------------------------------------------------------------- /src/pac_cstr.cc: -------------------------------------------------------------------------------- 1 | #include "pac_cstr.h" 2 | 3 | #include "pac_dbg.h" 4 | #include "pac_exception.h" 5 | 6 | namespace { 7 | 8 | class EscapeException { 9 | public: 10 | explicit EscapeException(const string& s) { msg_ = s; } 11 | 12 | const string& msg() const { return msg_; } 13 | 14 | private: 15 | string msg_; 16 | }; 17 | 18 | // Copied from util.cc of Zeek 19 | int expand_escape(const char*& s) { 20 | switch ( *(s++) ) { 21 | case 'b': return '\b'; 22 | case 'f': return '\f'; 23 | case 'n': return '\n'; 24 | case 'r': return '\r'; 25 | case 't': return '\t'; 26 | case 'a': return '\a'; 27 | case 'v': return '\v'; 28 | 29 | case '0': 30 | case '1': 31 | case '2': 32 | case '3': 33 | case '4': 34 | case '5': 35 | case '6': 36 | case '7': { // \{1,3} 37 | --s; // put back the first octal digit 38 | const char* start = s; 39 | 40 | // Don't increment inside loop control 41 | // because if isdigit() is a macro it might 42 | // expand into multiple increments ... 43 | 44 | // Here we define a maximum length for escape sequence 45 | // to allow easy handling of string like: "^H0" as 46 | // "\0100". 47 | 48 | for ( int len = 0; len < 3 && isascii(*s) && isdigit(*s); ++s, ++len ) 49 | ; 50 | 51 | int result; 52 | if ( sscanf(start, "%3o", &result) != 1 ) 53 | throw EscapeException(strfmt("bad octal escape: \"%s", start)); 54 | 55 | return result; 56 | } 57 | 58 | case 'x': { /* \x */ 59 | const char* start = s; 60 | 61 | // Look at most 2 characters, so that "\x0ddir" -> "^Mdir". 62 | for ( int len = 0; len < 2 && isascii(*s) && isxdigit(*s); ++s, ++len ) 63 | ; 64 | 65 | int result; 66 | if ( sscanf(start, "%2x", &result) != 1 ) 67 | throw EscapeException(strfmt("bad hexadecimal escape: \"%s", start)); 68 | 69 | return result; 70 | } 71 | 72 | default: return s[-1]; 73 | } 74 | } 75 | 76 | } // namespace 77 | 78 | ConstString::ConstString(const string& s) : str_(s) { 79 | // Copied from scan.l of Zeek 80 | try { 81 | const char* text = str_.c_str(); 82 | int len = strlen(text) + 1; 83 | int i = 0; 84 | 85 | char* new_s = new char[len]; 86 | 87 | // Skip leading quote. 88 | for ( ++text; *text; ++text ) { 89 | if ( *text == '\\' ) { 90 | ++text; // skip '\' 91 | new_s[i++] = expand_escape(text); 92 | --text; // point to end of sequence 93 | } 94 | else { 95 | new_s[i++] = *text; 96 | } 97 | } 98 | ASSERT(i < len); 99 | 100 | // Get rid of trailing quote. 101 | ASSERT(new_s[i - 1] == '"'); 102 | new_s[i - 1] = '\0'; 103 | 104 | unescaped_ = new_s; 105 | delete[] new_s; 106 | } catch ( EscapeException const& e ) { 107 | // Throw again with the object 108 | throw Exception(this, e.msg().c_str()); 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/pac_btype.cc: -------------------------------------------------------------------------------- 1 | #include "pac_btype.h" 2 | 3 | #include "pac_dataptr.h" 4 | #include "pac_id.h" 5 | #include "pac_output.h" 6 | 7 | Type* BuiltInType::DoClone() const { return new BuiltInType(bit_type()); } 8 | 9 | bool BuiltInType::IsNumericType() const { 10 | BITType t = bit_type(); 11 | return (t == INT8 || t == INT16 || t == INT32 || t == INT64 || t == UINT8 || t == UINT16 || t == UINT32 || 12 | t == UINT64); 13 | } 14 | 15 | bool BuiltInType::CompatibleBuiltInTypes(BuiltInType* type1, BuiltInType* type2) { 16 | return type1->IsNumericType() && type2->IsNumericType(); 17 | } 18 | 19 | static const char* basic_pactype_name[] = { 20 | #define TYPE_DEF(name, pactype, ctype, size) pactype, 21 | #include "pac_type.def" 22 | #undef TYPE_DEF 23 | nullptr, 24 | }; 25 | 26 | void BuiltInType::static_init() { 27 | for ( int bit_type = 0; basic_pactype_name[bit_type]; ++bit_type ) { 28 | Type::AddPredefinedType(basic_pactype_name[bit_type], new BuiltInType((BITType)bit_type)); 29 | } 30 | } 31 | 32 | int BuiltInType::LookUpByName(const char* name) { 33 | ASSERT(0); 34 | for ( int i = 0; basic_pactype_name[i]; ++i ) 35 | if ( strcmp(basic_pactype_name[i], name) == 0 ) 36 | return i; 37 | return -1; 38 | } 39 | 40 | static const char* basic_ctype_name[] = { 41 | #define TYPE_DEF(name, pactype, ctype, size) ctype, 42 | #include "pac_type.def" 43 | #undef TYPE_DEF 44 | nullptr, 45 | }; 46 | 47 | bool BuiltInType::DefineValueVar() const { return bit_type_ != EMPTY; } 48 | 49 | string BuiltInType::DataTypeStr() const { return basic_ctype_name[bit_type_]; } 50 | 51 | int BuiltInType::StaticSize(Env* /* env */) const { 52 | static const size_t basic_type_size[] = { 53 | #define TYPE_DEF(name, pactype, ctype, size) size, 54 | #include "pac_type.def" 55 | #undef TYPE_DEF 56 | }; 57 | 58 | return basic_type_size[bit_type_]; 59 | } 60 | 61 | void BuiltInType::DoMarkIncrementalInput() { 62 | if ( bit_type_ == EMPTY ) 63 | return; 64 | Type::DoMarkIncrementalInput(); 65 | } 66 | 67 | void BuiltInType::GenInitCode(Output* out_cc, Env* env) { 68 | if ( bit_type_ != EMPTY ) 69 | out_cc->println("%s = 0;", env->LValue(value_var())); 70 | Type::GenInitCode(out_cc, env); 71 | } 72 | 73 | void BuiltInType::GenDynamicSize(Output* out_cc, Env* env, const DataPtr& data) { 74 | /* should never be called */ 75 | ASSERT(0); 76 | } 77 | 78 | void BuiltInType::DoGenParseCode(Output* out_cc, Env* env, const DataPtr& data, int flags) { 79 | if ( bit_type_ == EMPTY ) 80 | return; 81 | 82 | // There is no need to generate the size variable 83 | // out_cc->println("%s = sizeof(%s);", size_var(), DataTypeStr().c_str()); 84 | 85 | GenBoundaryCheck(out_cc, env, data); 86 | 87 | if ( anonymous_value_var() ) 88 | return; 89 | 90 | switch ( bit_type_ ) { 91 | case EMPTY: 92 | // do nothing 93 | break; 94 | 95 | case INT8: 96 | case UINT8: 97 | out_cc->println("%s = *((%s const*)(%s));", lvalue(), DataTypeStr().c_str(), data.ptr_expr()); 98 | break; 99 | case INT16: 100 | case UINT16: 101 | case INT32: 102 | case UINT32: 103 | case INT64: 104 | case UINT64: 105 | #if 0 106 | out_cc->println("%s = UnMarshall<%s>(%s, %s);", 107 | lvalue(), 108 | DataTypeStr().c_str(), 109 | data.ptr_expr(), 110 | EvalByteOrder(out_cc, env).c_str()); 111 | #else 112 | out_cc->println("%s = FixByteOrder(%s, *((%s const*)(%s)));", lvalue(), EvalByteOrder(out_cc, env).c_str(), 113 | DataTypeStr().c_str(), data.ptr_expr()); 114 | #endif 115 | break; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/pac_let.cc: -------------------------------------------------------------------------------- 1 | #include "pac_let.h" 2 | 3 | #include "pac_expr.h" 4 | #include "pac_exttype.h" 5 | #include "pac_output.h" 6 | #include "pac_type.h" 7 | 8 | namespace { 9 | 10 | void GenLetEval(const ID* id, Expr* expr, string prefix, Output* out, Env* env) {} 11 | 12 | } // namespace 13 | 14 | LetField::LetField(ID* id, Type* type, Expr* expr) 15 | : Field(LET_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type), expr_(expr) { 16 | ASSERT(expr_); 17 | } 18 | 19 | LetField::~LetField() { delete expr_; } 20 | 21 | bool LetField::DoTraverse(DataDepVisitor* visitor) { return Field::DoTraverse(visitor) && expr()->Traverse(visitor); } 22 | 23 | bool LetField::RequiresAnalyzerContext() const { 24 | return Field::RequiresAnalyzerContext() || (expr() && expr()->RequiresAnalyzerContext()); 25 | } 26 | 27 | void LetField::Prepare(Env* env) { 28 | if ( ! type_ ) { 29 | ASSERT(expr_); 30 | type_ = expr_->DataType(env); 31 | if ( type_ ) 32 | type_ = type_->Clone(); 33 | else 34 | type_ = extern_type_int->Clone(); 35 | 36 | foreach (i, AttrList, attrs_) 37 | ProcessAttr(*i); 38 | } 39 | 40 | Field::Prepare(env); 41 | env->SetEvalMethod(id_, this); 42 | } 43 | 44 | void LetField::GenInitCode(Output* out_cc, Env* env) { 45 | int v; 46 | if ( expr_ && expr_->ConstFold(env, &v) ) { 47 | DEBUG_MSG("Folding const for `%s'\n", id_->Name()); 48 | GenEval(out_cc, env); 49 | } 50 | else 51 | type_->GenInitCode(out_cc, env); 52 | } 53 | 54 | void LetField::GenParseCode(Output* out_cc, Env* env) { 55 | if ( env->Evaluated(id_) ) 56 | return; 57 | 58 | if ( type_->attr_if_expr() ) { 59 | // A conditional field 60 | 61 | env->Evaluate(out_cc, type_->has_value_var()); 62 | 63 | // force evaluation of IDs contained in this expr 64 | expr()->ForceIDEval(out_cc, env); 65 | 66 | out_cc->println("if ( %s ) {", env->RValue(type_->has_value_var())); 67 | out_cc->inc_indent(); 68 | } 69 | 70 | out_cc->println("%s = %s;", env->LValue(id_), expr()->EvalExpr(out_cc, env)); 71 | if ( ! env->Evaluated(id_) ) 72 | env->SetEvaluated(id_); 73 | 74 | if ( type_->attr_if_expr() ) { 75 | out_cc->dec_indent(); 76 | out_cc->println("}"); 77 | } 78 | } 79 | 80 | void LetField::GenEval(Output* out_cc, Env* env) { GenParseCode(out_cc, env); } 81 | 82 | LetDecl::LetDecl(ID* id, Type* type, Expr* expr) : Decl(id, LET), type_(type), expr_(expr) { 83 | if ( ! type_ ) { 84 | ASSERT(expr_); 85 | type_ = expr_->DataType(global_env()); 86 | if ( type_ ) 87 | type_ = type_->Clone(); 88 | else 89 | type_ = extern_type_int->Clone(); 90 | } 91 | 92 | Env* env = global_env(); 93 | int c; 94 | if ( expr_ && expr_->ConstFold(env, &c) ) 95 | env->AddConstID(id_, c, type); 96 | else 97 | env->AddID(id_, GLOBAL_VAR, type_); 98 | } 99 | 100 | LetDecl::~LetDecl() { 101 | delete type_; 102 | delete expr_; 103 | } 104 | 105 | void LetDecl::Prepare() {} 106 | 107 | void LetDecl::GenForwardDeclaration(Output* out_h) {} 108 | 109 | void LetDecl::GenCode(Output* out_h, Output* out_cc) { 110 | out_h->println("extern %s const %s;", type_->DataTypeStr().c_str(), global_env()->RValue(id_)); 111 | GenEval(out_cc, global_env()); 112 | } 113 | 114 | void LetDecl::GenEval(Output* out_cc, Env* /* env */) { 115 | Env* env = global_env(); 116 | string tmp = strfmt("%s const", type_->DataTypeStr().c_str()); 117 | out_cc->println("%s %s = %s;", tmp.c_str(), env->LValue(id_), expr_->EvalExpr(out_cc, env)); 118 | 119 | if ( ! env->Evaluated(id_) ) 120 | env->SetEvaluated(id_); 121 | } 122 | -------------------------------------------------------------------------------- /src/pac_field.cc: -------------------------------------------------------------------------------- 1 | #include "pac_field.h" 2 | 3 | #include "pac_attr.h" 4 | #include "pac_common.h" 5 | #include "pac_exception.h" 6 | #include "pac_id.h" 7 | #include "pac_type.h" 8 | 9 | Field::Field(FieldType tof, int flags, ID* id, Type* type) 10 | : DataDepElement(DataDepElement::FIELD), tof_(tof), flags_(flags), id_(id), type_(type) { 11 | decl_id_ = current_decl_id; 12 | field_id_str_ = strfmt("%s:%s", decl_id()->Name(), id_->Name()); 13 | attrs_ = nullptr; 14 | } 15 | 16 | Field::~Field() { 17 | delete id_; 18 | delete type_; 19 | delete_list(AttrList, attrs_); 20 | } 21 | 22 | void Field::AddAttr(AttrList* attrs) { 23 | bool delete_attrs = false; 24 | 25 | if ( ! attrs_ ) { 26 | attrs_ = attrs; 27 | } 28 | else { 29 | attrs_->insert(attrs_->end(), attrs->begin(), attrs->end()); 30 | delete_attrs = true; 31 | } 32 | 33 | foreach (i, AttrList, attrs) 34 | ProcessAttr(*i); 35 | 36 | if ( delete_attrs ) 37 | delete attrs; 38 | } 39 | 40 | void Field::ProcessAttr(Attr* a) { 41 | switch ( a->type() ) { 42 | case ATTR_IF: 43 | if ( tof() != LET_FIELD && tof() != WITHINPUT_FIELD ) { 44 | throw Exception(a, 45 | "&if can only be applied to a " 46 | "let field"); 47 | } 48 | break; 49 | default: break; 50 | } 51 | 52 | if ( type_ ) 53 | type_->ProcessAttr(a); 54 | } 55 | 56 | bool Field::anonymous_field() const { return type_ && type_->anonymous_value_var(); } 57 | 58 | int Field::ValueVarType() const { 59 | if ( flags_ & CLASS_MEMBER ) 60 | return (flags_ & PUBLIC_READABLE) ? MEMBER_VAR : PRIV_MEMBER_VAR; 61 | else 62 | return TEMP_VAR; 63 | } 64 | 65 | void Field::Prepare(Env* env) { 66 | if ( type_ ) { 67 | if ( anonymous_field() ) 68 | flags_ &= ~(CLASS_MEMBER | PUBLIC_READABLE); 69 | if ( ! type_->persistent() ) 70 | flags_ &= (~PUBLIC_READABLE); 71 | 72 | type_->set_value_var(id(), ValueVarType()); 73 | type_->Prepare(env, flags_ & TYPE_TO_BE_PARSED ? Type::TO_BE_PARSED : 0); 74 | env->SetField(id(), this); 75 | } 76 | } 77 | 78 | void Field::GenPubDecls(Output* out_h, Env* env) { 79 | if ( type_ && (flags_ & PUBLIC_READABLE) && (flags_ & CLASS_MEMBER) ) 80 | type_->GenPubDecls(out_h, env); 81 | } 82 | 83 | void Field::GenPrivDecls(Output* out_h, Env* env) { 84 | // Generate private declaration only if it is a class member 85 | if ( type_ && (flags_ & CLASS_MEMBER) ) 86 | type_->GenPrivDecls(out_h, env); 87 | } 88 | 89 | void Field::GenTempDecls(Output* out_h, Env* env) { 90 | // Generate temp field 91 | if ( type_ && ! (flags_ & CLASS_MEMBER) ) 92 | type_->GenPrivDecls(out_h, env); 93 | } 94 | 95 | void Field::GenInitCode(Output* out_cc, Env* env) { 96 | if ( type_ && ! anonymous_field() ) 97 | type_->GenInitCode(out_cc, env); 98 | } 99 | 100 | void Field::GenCleanUpCode(Output* out_cc, Env* env) { 101 | if ( type_ && ! anonymous_field() ) 102 | type_->GenCleanUpCode(out_cc, env); 103 | } 104 | 105 | bool Field::DoTraverse(DataDepVisitor* visitor) { 106 | // Check parameterized type 107 | if ( type_ && ! type_->Traverse(visitor) ) 108 | return false; 109 | foreach (i, AttrList, attrs_) 110 | if ( ! (*i)->Traverse(visitor) ) 111 | return false; 112 | return true; 113 | } 114 | 115 | bool Field::RequiresAnalyzerContext() const { 116 | // Check parameterized type 117 | if ( type_ && type_->RequiresAnalyzerContext() ) 118 | return true; 119 | foreach (i, AttrList, attrs_) 120 | if ( (*i)->RequiresAnalyzerContext() ) 121 | return true; 122 | return false; 123 | } 124 | -------------------------------------------------------------------------------- /src/pac_redef.cc: -------------------------------------------------------------------------------- 1 | #include "pac_redef.h" 2 | 3 | #include "pac_analyzer.h" 4 | #include "pac_case.h" 5 | #include "pac_exception.h" 6 | #include "pac_expr.h" 7 | #include "pac_func.h" 8 | #include "pac_record.h" 9 | #include "pac_type.h" 10 | #include "pac_typedecl.h" 11 | 12 | namespace { 13 | 14 | Decl* find_decl(const ID* id) { 15 | Decl* decl = Decl::LookUpDecl(id); 16 | if ( ! decl ) { 17 | throw Exception(id, strfmt("cannot find declaration for %s", id->Name())); 18 | } 19 | 20 | return decl; 21 | } 22 | 23 | } // namespace 24 | 25 | Decl* ProcessTypeRedef(const ID* id, FieldList* fieldlist) { 26 | Decl* decl = find_decl(id); 27 | 28 | if ( decl->decl_type() != Decl::TYPE ) { 29 | throw Exception(id, strfmt("not a type declaration: %s", id->Name())); 30 | } 31 | 32 | TypeDecl* type_decl = static_cast(decl); 33 | ASSERT(type_decl); 34 | Type* type = type_decl->type(); 35 | 36 | foreach (i, FieldList, fieldlist) { 37 | Field* f = *i; 38 | 39 | // One cannot change data layout in 'redef'. 40 | // Only 'let' or 'action' can be added 41 | if ( f->tof() == LET_FIELD || f->tof() == WITHINPUT_FIELD ) { 42 | type->AddField(f); 43 | } 44 | else if ( f->tof() == RECORD_FIELD || f->tof() == PADDING_FIELD ) { 45 | throw Exception(f, "cannot change data layout in redef"); 46 | } 47 | else if ( f->tof() == CASE_FIELD ) { 48 | throw Exception(f, "use 'redef case' adding cases"); 49 | } 50 | } 51 | 52 | return decl; 53 | } 54 | 55 | Decl* ProcessCaseTypeRedef(const ID* id, CaseFieldList* casefieldlist) { 56 | Decl* decl = find_decl(id); 57 | 58 | if ( decl->decl_type() != Decl::TYPE ) { 59 | throw Exception(id, strfmt("not a type declaration: %s", id->Name())); 60 | } 61 | 62 | TypeDecl* type_decl = static_cast(decl); 63 | ASSERT(type_decl); 64 | 65 | Type* type = type_decl->type(); 66 | if ( type->tot() != Type::CASE ) { 67 | throw Exception(id, strfmt("not a case type: %s", id->Name())); 68 | } 69 | 70 | CaseType* casetype = static_cast(type); 71 | ASSERT(casetype); 72 | 73 | foreach (i, CaseFieldList, casefieldlist) { 74 | CaseField* f = *i; 75 | casetype->AddCaseField(f); 76 | } 77 | 78 | return decl; 79 | } 80 | 81 | Decl* ProcessCaseExprRedef(const ID* id, CaseExprList* caseexprlist) { 82 | Decl* decl = find_decl(id); 83 | 84 | if ( decl->decl_type() != Decl::FUNC ) { 85 | throw Exception(id, strfmt("not a function declaration: %s", id->Name())); 86 | } 87 | 88 | FuncDecl* func_decl = static_cast(decl); 89 | ASSERT(func_decl); 90 | 91 | Expr* expr = func_decl->function()->expr(); 92 | if ( ! expr || expr->expr_type() != Expr::EXPR_CASE ) { 93 | throw Exception(id, strfmt("function not defined by a case expression: %s", id->Name())); 94 | } 95 | 96 | foreach (i, CaseExprList, caseexprlist) { 97 | CaseExpr* e = *i; 98 | expr->AddCaseExpr(e); 99 | } 100 | 101 | return decl; 102 | } 103 | 104 | Decl* ProcessAnalyzerRedef(const ID* id, Decl::DeclType decl_type, AnalyzerElementList* elements) { 105 | Decl* decl = find_decl(id); 106 | 107 | if ( decl->decl_type() != decl_type ) { 108 | throw Exception(id, strfmt("not a connection/flow declaration: %s", id->Name())); 109 | } 110 | 111 | AnalyzerDecl* analyzer_decl = static_cast(decl); 112 | ASSERT(analyzer_decl); 113 | 114 | analyzer_decl->AddElements(elements); 115 | 116 | return decl; 117 | } 118 | 119 | Decl* ProcessTypeAttrRedef(const ID* id, AttrList* attrlist) { 120 | Decl* decl = find_decl(id); 121 | 122 | if ( decl->decl_type() != Decl::TYPE ) { 123 | throw Exception(id, strfmt("not a type declaration: %s", id->Name())); 124 | } 125 | 126 | TypeDecl* type_decl = static_cast(decl); 127 | ASSERT(type_decl); 128 | 129 | type_decl->AddAttrs(attrlist); 130 | 131 | return decl; 132 | } 133 | -------------------------------------------------------------------------------- /patches/binpac-patch-doc.txt: -------------------------------------------------------------------------------- 1 | binpac fixes 2 | ---------------- 3 | 4 | numbers of issues below correspond to the patch numbers 5 | 6 | (1) correct calculation of minimal header size in pac_expr.cc 7 | - problem: EXPR_CALLARGS and EXPR_CASE not considered for the calculation 8 | of minimal header size 9 | - solution: added two cases in switch stmt of Expr::MinimalHeaderSize 10 | for EXPR_CALLARGS and EXPR_CASE 11 | 12 | 13 | (2) ensure parsing of fields first referenced in a case expression or 14 | let field with an &if attribute 15 | - problem: in cases where the if expression evaluates to false or the 16 | proper case does not occur, fields get not parsed at all 17 | - solution: force evaluation of all IDs referenced in a let field with 18 | if attribute or a case expression before the body of the corresponding 19 | switch stmt or the if stmt 20 | - added public method Expr::ForceIDEval, properly called before 21 | generating the code of a field with if attribute or the case expression 22 | 23 | 24 | (3) properly assert the use of fields with an if attribute 25 | - problem: the use of fields with an if attribute was not asserted in all 26 | cases and asserted in the wrong way in some others due to the 27 | corresponding BINPAC_ASSERT only called upon parsing the field 28 | - solution: perform BINPAC_ASSERT upon calling the fields accessor 29 | function 30 | - moved BINPAC_ASSERT statement from LetField::GenEval to 31 | Type::GenPubDecls 32 | 33 | 34 | (4) incremental input with records with a non-negative StaticSize 35 | - problem: incremental input with records with a StaticSize >= 0 36 | cannot be performed due to necessary length attribute, leading to 37 | an invalid call of GenBoundaryCheck in RecordType::DoGenParseCode 38 | - solution: added a check for incremental input in 39 | RecordType::DoGenParseCode before calling GenBoundaryCheck 40 | 41 | 42 | (5) empty type with incremental input 43 | - problem: with an empty type and incremental input, although the 44 | Parse function is created, it is never called, leading to problems, 45 | if additional actions are to be performed when encountering that 46 | empty type 47 | - solution: generate call to Parse of empty type in Type::GenParseBuffer 48 | 49 | 50 | (6) parsing loop in flow ParseBuffer (while(true)) 51 | - problem: while(true) leads to problems after parsing of a type is 52 | complete; at this time, it is unexpected that parsing continues, even 53 | if no data is available in the flow buffer 54 | - solution: check if data is available before starting a new parsing 55 | cycle 56 | - added a method data_available to FlowBuffer 57 | - changed while(true) in FlowDecl::GenCodeFlowUnit to 58 | while(flow_buffer_->data_available()) 59 | 60 | 61 | (7) initialization of flow buffer in CaseType with bufferable fields 62 | in cases 63 | - problem: initialization of buffer occurs in every Parse call, 64 | regardless if it was initialized before or not; initialization 65 | is correct only on first such occurrence 66 | - solution: check to buffer_state is to be created always when 67 | buffering_state_id is in environment in Type::GenBufferConfig 68 | - changed condition from buffering_state_var_field_ to 69 | env->GetDataType(buffering_state_id) 70 | 71 | 72 | (8) allowing init and cleanup code to be redefined, as well as addition 73 | of code to FlowEOF calls in analyzer and flow 74 | - problem 1: when refining an analyzer or flow definition, additional 75 | init and cleanup code was not allowed, if these were already defined 76 | before; this leads to problems when adding new members, as these 77 | cannot be initialized and destroyed properly 78 | - solution: allow init and cleanup code to be specified more than once 79 | - changed deifnitions and usage of constructor_helper and 80 | destructor_helper to allow for lists of constructor and destructor 81 | helpers (similar to member declarations) in pac_analyzer.h and 82 | pac_analyzer.cc 83 | - problem 2: in some cases, it is desirable to execute code when 84 | encountering the end of the input stream, which is not possible in 85 | binpac 86 | - solution: added a %eof binpac primitive similar to %init, which adds 87 | code to the FlowEOF function of an analyzer or a flow 88 | -------------------------------------------------------------------------------- /lib/binpac_bytestring.h: -------------------------------------------------------------------------------- 1 | #ifndef binpac_bytestring_h 2 | #define binpac_bytestring_h 3 | 4 | #include 5 | #include 6 | 7 | #include "binpac.h" 8 | 9 | namespace binpac { 10 | 11 | template 12 | class datastring; 13 | 14 | template 15 | class const_datastring { 16 | public: 17 | const_datastring() : begin_(0), end_(0) {} 18 | 19 | const_datastring(T const* data, int length) : begin_(data), end_(data + length) {} 20 | 21 | const_datastring(const T* begin, const T* end) : begin_(begin), end_(end) {} 22 | 23 | const_datastring(datastring const& s) : begin_(s.begin()), end_(s.end()) {} 24 | 25 | void init(const T* data, int length) { 26 | begin_ = data; 27 | end_ = data + length; 28 | } 29 | 30 | T const* begin() const { return begin_; } 31 | T const* end() const { return end_; } 32 | int length() const { return end_ - begin_; } 33 | 34 | T const& operator[](int index) const { return begin()[index]; } 35 | 36 | bool operator==(const_datastring const& s) { 37 | if ( length() != s.length() ) 38 | return false; 39 | return memcmp((const void*)begin(), (const void*)s.begin(), sizeof(T) * length()) == 0; 40 | } 41 | 42 | void set_begin(T const* begin) { begin_ = begin; } 43 | void set_end(T const* end) { end_ = end; } 44 | 45 | private: 46 | T const* begin_; 47 | T const* end_; 48 | }; 49 | 50 | typedef const_datastring const_bytestring; 51 | 52 | template 53 | class datastring { 54 | public: 55 | datastring() { clear(); } 56 | 57 | datastring(T* data, int len) { set(data, len); } 58 | 59 | datastring(T const* begin, T const* end) { set_const(begin, end - begin); } 60 | 61 | datastring(datastring const& x) : data_(x.data()), length_(x.length()) {} 62 | 63 | explicit datastring(const_datastring const& x) { set_const(x.begin(), x.length()); } 64 | 65 | datastring const& operator=(datastring const& x) { 66 | BINPAC_ASSERT(! data_); 67 | set(x.data(), x.length()); 68 | return *this; 69 | } 70 | 71 | void init(T const* begin, int length) { 72 | BINPAC_ASSERT(! data_); 73 | set_const(begin, length); 74 | } 75 | 76 | void clear() { 77 | data_ = 0; 78 | length_ = 0; 79 | } 80 | 81 | void free() { 82 | if ( data_ ) 83 | delete[] data_; 84 | clear(); 85 | } 86 | 87 | void clone() { set_const(begin(), length()); } 88 | 89 | datastring const& operator=(const_datastring const& x) { 90 | BINPAC_ASSERT(! data_); 91 | set_const(x.begin(), x.length()); 92 | return *this; 93 | } 94 | 95 | T const& operator[](int index) const { return begin()[index]; } 96 | 97 | T* data() const { return data_; } 98 | int length() const { return length_; } 99 | 100 | T const* begin() const { return data_; } 101 | T const* end() const { return data_ + length_; } 102 | 103 | private: 104 | void set(T* data, int len) { 105 | data_ = data; 106 | length_ = len; 107 | } 108 | 109 | void set_const(T const* data, int len) { 110 | length_ = len; 111 | data_ = new T[len + 1]; 112 | memcpy(data_, data, sizeof(T) * len); 113 | data_[len] = 0; 114 | } 115 | 116 | T* data_; 117 | int length_; 118 | }; 119 | 120 | typedef datastring bytestring; 121 | 122 | inline const char* c_str(bytestring const& s) { return (const char*)s.begin(); } 123 | 124 | inline std::string std_str(const_bytestring const& s) { 125 | return std::string((const char*)s.begin(), (const char*)s.end()); 126 | } 127 | 128 | inline bool operator==(bytestring const& s1, const char* s2) { return strcmp(c_str(s1), s2) == 0; } 129 | 130 | inline void get_pointers(const_bytestring const& s, uint8 const** pbegin, uint8 const** pend) { 131 | *pbegin = s.begin(); 132 | *pend = s.end(); 133 | } 134 | 135 | inline void get_pointers(bytestring const* s, uint8 const** pbegin, uint8 const** pend) { 136 | *pbegin = s->begin(); 137 | *pend = s->end(); 138 | } 139 | 140 | } // namespace binpac 141 | 142 | #endif // binpac_bytestring_h 143 | -------------------------------------------------------------------------------- /lib/binpac.h.in: -------------------------------------------------------------------------------- 1 | // Do not edit binpac.h, edit binpac.h.in instead! 2 | 3 | #ifndef binpac_h 4 | #define binpac_h 5 | 6 | #ifndef _MSC_VER 7 | #include 8 | #endif 9 | 10 | #cmakedefine HOST_BIGENDIAN 11 | #ifdef HOST_BIGENDIAN 12 | # define HOST_BYTEORDER bigendian 13 | #else 14 | # define HOST_BYTEORDER littleendian 15 | #endif 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | // Expose C99 functionality from inttypes.h, which would otherwise not be 24 | // available in C++. 25 | #ifndef __STDC_FORMAT_MACROS 26 | #define __STDC_FORMAT_MACROS 27 | #endif 28 | 29 | #include 30 | 31 | #define BINPAC_ASSERT(x) assert(x) 32 | 33 | using namespace std; 34 | 35 | namespace binpac { 36 | 37 | const int bigendian = 0; 38 | const int littleendian = 1; 39 | const int unspecified_byteorder = -1; 40 | 41 | #ifndef pac_type_defs 42 | #define pac_type_defs 43 | 44 | typedef int8_t int8; 45 | typedef int16_t int16; 46 | typedef int32_t int32; 47 | typedef int64_t int64; 48 | typedef uint8_t uint8; 49 | typedef uint16_t uint16; 50 | typedef uint32_t uint32; 51 | typedef uint64_t uint64; 52 | typedef void *nulptr; 53 | typedef void *voidptr; 54 | typedef uint8 *byteptr; 55 | typedef const uint8 *const_byteptr; 56 | typedef const char *const_charptr; 57 | 58 | #if @SIZEOF_UNSIGNED_INT@ != 4 59 | #error "unexpected size of unsigned int" 60 | #endif 61 | 62 | #endif /* pac_type_defs */ 63 | 64 | /* Handling byte order */ 65 | 66 | namespace { 67 | 68 | inline uint16 pac_swap(const uint16 x) 69 | { 70 | return (x >> 8) | ((x & 0xff) << 8); 71 | } 72 | 73 | inline int16 pac_swap(const int16 x) 74 | { 75 | // Forward to unsigned version with argument/result casted 76 | // appropriately. 77 | uint16 (*p)(const uint16) = &pac_swap; 78 | return (*p)(x); 79 | } 80 | 81 | inline uint32 pac_swap(const uint32 x) 82 | { 83 | return (x >> 24) | 84 | ((x & 0xff0000) >> 8) | 85 | ((x & 0xff00) << 8) | 86 | ((x & 0xff) << 24); 87 | } 88 | 89 | inline int32 pac_swap(const int32 x) 90 | { 91 | // Forward to unsigned version with argument/result casted 92 | // appropriately. 93 | uint32 (*p)(const uint32) = &pac_swap; 94 | return (*p)(x); 95 | } 96 | 97 | inline uint64 pac_swap(const uint64 x) 98 | { 99 | return x >> 56 | 100 | (x & 0xff000000000000) >> 40 | 101 | (x & 0xff0000000000) >> 24 | 102 | (x & 0xff00000000) >> 8 | 103 | (x & 0xff000000) << 8 | 104 | (x & 0xff0000) << 24 | 105 | (x & 0xff00) << 40 | 106 | (x & 0xff) << 56; 107 | } 108 | 109 | inline int64 pac_swap(const int64 x) 110 | { 111 | // Forward to unsigned version with argument/result casted 112 | // appropriately. 113 | uint64 (*p)(const uint64) = &pac_swap; 114 | return (*p)(x); 115 | } 116 | 117 | #define FixByteOrder(byteorder, x) (byteorder == HOST_BYTEORDER ? (x) : pac_swap(x)) 118 | 119 | template 120 | inline T UnMarshall(const unsigned char *data, int byteorder) 121 | { 122 | T result = 0; 123 | for ( int i = 0; i < (int) sizeof(T); ++i ) 124 | result = ( result << 8 ) | 125 | data[byteorder == bigendian ? i : sizeof(T) - 1 - i]; 126 | return result; 127 | } 128 | 129 | inline const char* do_fmt(const char* format, va_list ap) 130 | { 131 | static char buf[1024]; 132 | vsnprintf(buf, sizeof(buf), format, ap); 133 | return buf; 134 | } 135 | 136 | inline string strfmt(const char* format, ...) 137 | { 138 | va_list ap; 139 | va_start(ap, format); 140 | const char* r = do_fmt(format, ap); 141 | va_end(ap); 142 | return string(r); 143 | } 144 | 145 | } // anonymous namespace 146 | 147 | #define binpac_fmt(...) strfmt(__VA_ARGS__).c_str() 148 | 149 | class RefCount 150 | { 151 | public: 152 | RefCount() { count = 1; } 153 | virtual ~RefCount() {} 154 | void Ref() { ++count; } 155 | int Unref() { BINPAC_ASSERT(count > 0); return --count; } 156 | 157 | private: 158 | int count; 159 | }; 160 | 161 | namespace { 162 | inline void Unref(RefCount *x) 163 | { 164 | if ( x && x->Unref() <= 0 ) 165 | delete x; 166 | } 167 | } // anonymous namespace 168 | 169 | } // namespace binpac 170 | 171 | #include "binpac_analyzer.h" 172 | #include "binpac_buffer.h" 173 | #include "binpac_bytestring.h" 174 | #include "binpac_exception.h" 175 | #include "binpac_regex.h" 176 | 177 | #endif /* binpac_h */ 178 | -------------------------------------------------------------------------------- /src/pac_conn.cc: -------------------------------------------------------------------------------- 1 | #include "pac_conn.h" 2 | 3 | #include "pac_analyzer.h" 4 | #include "pac_dataunit.h" 5 | #include "pac_embedded.h" 6 | #include "pac_exception.h" 7 | #include "pac_expr.h" 8 | #include "pac_flow.h" 9 | #include "pac_output.h" 10 | #include "pac_paramtype.h" 11 | #include "pac_type.h" 12 | 13 | ConnDecl::ConnDecl(ID* conn_id, ParamList* params, AnalyzerElementList* elemlist) 14 | : AnalyzerDecl(conn_id, CONN, params) { 15 | flows_[0] = flows_[1] = nullptr; 16 | AddElements(elemlist); 17 | data_type_ = new ParameterizedType(conn_id->clone(), nullptr); 18 | } 19 | 20 | ConnDecl::~ConnDecl() { 21 | delete flows_[0]; 22 | delete flows_[1]; 23 | delete data_type_; 24 | } 25 | 26 | void ConnDecl::AddBaseClass(vector* base_classes) const { 27 | base_classes->push_back("binpac::ConnectionAnalyzer"); 28 | } 29 | 30 | void ConnDecl::ProcessFlowElement(AnalyzerFlow* flow_elem) { 31 | int flow_index; 32 | 33 | if ( flow_elem->dir() == AnalyzerFlow::UP ) 34 | flow_index = 0; 35 | else 36 | flow_index = 1; 37 | 38 | if ( flows_[flow_index] ) { 39 | throw Exception(flow_elem, strfmt("%sflow already defined", flow_index == 0 ? "up" : "down")); 40 | } 41 | 42 | flows_[flow_index] = flow_elem; 43 | type_->AddField(flow_elem->flow_field()); 44 | } 45 | 46 | void ConnDecl::ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) { 47 | throw Exception(dataunit_elem, "dataunit should be defined in only a flow declaration"); 48 | } 49 | 50 | void ConnDecl::Prepare() { 51 | AnalyzerDecl::Prepare(); 52 | 53 | flows_[0]->flow_decl()->set_conn_decl(this); 54 | flows_[1]->flow_decl()->set_conn_decl(this); 55 | } 56 | 57 | void ConnDecl::GenPubDecls(Output* out_h, Output* out_cc) { AnalyzerDecl::GenPubDecls(out_h, out_cc); } 58 | 59 | void ConnDecl::GenPrivDecls(Output* out_h, Output* out_cc) { AnalyzerDecl::GenPrivDecls(out_h, out_cc); } 60 | 61 | void ConnDecl::GenEOFFunc(Output* out_h, Output* out_cc) { 62 | string proto = strfmt("%s(bool is_orig)", kFlowEOF); 63 | 64 | out_h->println("void %s;", proto.c_str()); 65 | 66 | out_cc->println("void %s::%s {", class_name().c_str(), proto.c_str()); 67 | out_cc->inc_indent(); 68 | 69 | out_cc->println("if ( is_orig )"); 70 | out_cc->inc_indent(); 71 | out_cc->println("%s->%s();", env_->LValue(upflow_id), kFlowEOF); 72 | out_cc->dec_indent(); 73 | out_cc->println("else"); 74 | out_cc->inc_indent(); 75 | out_cc->println("%s->%s();", env_->LValue(downflow_id), kFlowEOF); 76 | 77 | foreach (i, AnalyzerHelperList, eof_helpers_) { 78 | (*i)->GenCode(nullptr, out_cc, this); 79 | } 80 | 81 | out_cc->dec_indent(); 82 | 83 | out_cc->dec_indent(); 84 | out_cc->println("}"); 85 | out_cc->println(""); 86 | } 87 | 88 | void ConnDecl::GenGapFunc(Output* out_h, Output* out_cc) { 89 | string proto = strfmt("%s(bool is_orig, int gap_length)", kFlowGap); 90 | 91 | out_h->println("void %s;", proto.c_str()); 92 | 93 | out_cc->println("void %s::%s {", class_name().c_str(), proto.c_str()); 94 | out_cc->inc_indent(); 95 | 96 | out_cc->println("if ( is_orig )"); 97 | out_cc->inc_indent(); 98 | out_cc->println("%s->%s(gap_length);", env_->LValue(upflow_id), kFlowGap); 99 | out_cc->dec_indent(); 100 | out_cc->println("else"); 101 | out_cc->inc_indent(); 102 | out_cc->println("%s->%s(gap_length);", env_->LValue(downflow_id), kFlowGap); 103 | out_cc->dec_indent(); 104 | 105 | out_cc->dec_indent(); 106 | out_cc->println("}"); 107 | out_cc->println(""); 108 | } 109 | 110 | void ConnDecl::GenProcessFunc(Output* out_h, Output* out_cc) { 111 | string proto = strfmt("%s(bool is_orig, const_byteptr begin, const_byteptr end)", kNewData); 112 | 113 | out_h->println("void %s override;", proto.c_str()); 114 | 115 | out_cc->println("void %s::%s {", class_name().c_str(), proto.c_str()); 116 | out_cc->inc_indent(); 117 | 118 | out_cc->println("if ( is_orig )"); 119 | out_cc->inc_indent(); 120 | out_cc->println("%s->%s(begin, end);", env_->LValue(upflow_id), kNewData); 121 | out_cc->dec_indent(); 122 | out_cc->println("else"); 123 | out_cc->inc_indent(); 124 | out_cc->println("%s->%s(begin, end);", env_->LValue(downflow_id), kNewData); 125 | out_cc->dec_indent(); 126 | 127 | out_cc->dec_indent(); 128 | out_cc->println("}"); 129 | out_cc->println(""); 130 | } 131 | -------------------------------------------------------------------------------- /src/pac_common.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_common_h 2 | #define pac_common_h 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "pac_utils.h" 10 | 11 | using namespace std; 12 | 13 | extern bool FLAGS_pac_debug; 14 | extern bool FLAGS_quiet; 15 | extern vector FLAGS_include_directories; 16 | extern string input_filename; 17 | extern int line_number; 18 | 19 | // Definition of class Object, which is the base class for all objects 20 | // representing language elements -- identifiers, types, expressions, 21 | // etc. 22 | 23 | class Object { 24 | public: 25 | Object() { 26 | filename = input_filename; 27 | line_num = line_number; 28 | location = strfmt("%s:%d", filename.c_str(), line_number); 29 | } 30 | 31 | ~Object() {} 32 | 33 | const char* Location() const { return location.c_str(); } 34 | 35 | protected: 36 | string filename; 37 | int line_num; 38 | string location; 39 | }; 40 | 41 | class ActionParam; 42 | class ActionParamType; 43 | class AnalyzerAction; 44 | class AnalyzerContextDecl; 45 | class AnalyzerDecl; 46 | class AnalyzerElement; 47 | class ArrayType; 48 | class Attr; 49 | class CClass; 50 | class CType; 51 | class ConstString; 52 | class CaseExpr; 53 | class CaseField; 54 | class ContextField; 55 | class DataPtr; 56 | class Decl; 57 | class EmbeddedCode; 58 | class Enum; 59 | class Env; 60 | class ExternType; 61 | class Expr; 62 | class Field; 63 | class Function; 64 | class InputBuffer; 65 | class LetDef; 66 | class LetField; 67 | class ID; 68 | class Nullptr; 69 | class Number; 70 | class Output; 71 | class PacPrimitive; 72 | class Param; 73 | class ParameterizedType; 74 | class RecordType; 75 | class RecordField; 76 | class RecordDataField; 77 | class RecordPaddingField; 78 | class RegEx; 79 | class SeqEnd; 80 | class StateVar; 81 | class Type; 82 | class TypeDecl; 83 | class WithInputField; 84 | 85 | // The ID of the current declaration. 86 | extern const ID* current_decl_id; 87 | 88 | typedef vector ActionParamList; 89 | typedef vector AnalyzerActionList; 90 | typedef vector AnalyzerElementList; 91 | typedef vector AttrList; 92 | typedef vector CaseExprList; 93 | typedef vector CaseFieldList; 94 | typedef vector ContextFieldList; 95 | typedef vector DeclList; 96 | typedef vector EnumList; 97 | typedef vector ExprList; 98 | typedef vector FieldList; 99 | typedef vector LetFieldList; 100 | typedef vector NumList; 101 | typedef vector ParamList; 102 | typedef vector RecordFieldList; 103 | typedef vector StateVarList; 104 | 105 | #define foreach(i, ct, pc) \ 106 | if ( pc ) \ 107 | for ( ct::iterator i = (pc)->begin(); i != (pc)->end(); ++i ) 108 | 109 | #define delete_list(ct, pc) \ 110 | { \ 111 | foreach (delete_list_i, ct, pc) \ 112 | delete *delete_list_i; \ 113 | delete pc; \ 114 | pc = 0; \ 115 | } 116 | 117 | // Constants 118 | const char* const kComputeFrameLength = "compute_frame_length"; 119 | const char* const kFlowBufferClass = "FlowBuffer"; 120 | const char* const kFlowBufferVar = "flow_buffer"; 121 | const char* const kFlowEOF = "FlowEOF"; 122 | const char* const kFlowGap = "NewGap"; 123 | const char* const kInitialBufferLengthFunc = "initial_buffer_length"; 124 | const char* const kNeedMoreData = "need_more_data"; 125 | const char* const kNewData = "NewData"; 126 | const char* const kParseFuncWithBuffer = "ParseBuffer"; 127 | const char* const kParseFuncWithoutBuffer = "Parse"; 128 | const char* const kRefCountClass = "binpac::RefCount"; 129 | const char* const kTypeWithLengthClass = "binpac::TypeWithLength"; 130 | 131 | #endif // pac_common_h 132 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Convenience wrapper for easily viewing/setting options that 3 | # the project's CMake scripts will recognize 4 | set -e 5 | command="$0 $*" 6 | 7 | # check for `cmake` command 8 | type cmake >/dev/null 2>&1 || { 9 | echo "\ 10 | This package requires CMake, please install it first, then you may 11 | use this configure script to access CMake equivalent functionality.\ 12 | " >&2 13 | exit 1 14 | } 15 | 16 | usage="\ 17 | Usage: $0 [OPTION]... [VAR=VALUE]... 18 | 19 | Build Directory: 20 | --builddir=DIR place build files in directory [build] 21 | --enable-static build static libraries (in addition to shared) 22 | --enable-static-only only build static libraries, not shared 23 | 24 | Installation Directories: 25 | --prefix=PREFIX installation directory [/usr/local] 26 | --libdir=DIR installation dir for libraries [PREFIX/lib] 27 | 28 | Optional Features: 29 | --enable-debug compile in debugging mode 30 | 31 | Required Packages in Non-Standard Locations: 32 | --with-openssl=PATH path to OpenSSL install root 33 | --with-bind=PATH path to BIND install root 34 | --with-pcap=PATH path to libpcap install root 35 | --with-flex=PATH path to flex executable 36 | --with-bison=PATH path to bison executable 37 | 38 | Influential Environment Variables (only on first invocation 39 | per build directory): 40 | CC C compiler command 41 | CFLAGS C compiler flags 42 | CXX C++ compiler command 43 | CXXFLAGS C++ compiler flags 44 | " 45 | 46 | sourcedir="$(cd "$(dirname "$0")" && pwd)" 47 | 48 | # Function to append a CMake cache entry definition to the 49 | # CMakeCacheEntries variable 50 | # $1 is the cache entry variable name 51 | # $2 is the cache entry variable type 52 | # $3 is the cache entry variable value 53 | append_cache_entry() { 54 | CMakeCacheEntries="$CMakeCacheEntries -D $1:$2=$3" 55 | } 56 | 57 | # set defaults 58 | builddir=build 59 | CMakeCacheEntries="" 60 | append_cache_entry CMAKE_INSTALL_PREFIX PATH /usr/local 61 | append_cache_entry ENABLE_DEBUG BOOL false 62 | 63 | # parse arguments 64 | while [ $# -ne 0 ]; do 65 | case "$1" in 66 | -*=*) optarg=$(echo "$1" | sed 's/[-_a-zA-Z0-9]*=//') ;; 67 | *) optarg= ;; 68 | esac 69 | 70 | case "$1" in 71 | --help | -h) 72 | echo "${usage}" 1>&2 73 | exit 1 74 | ;; 75 | --builddir=*) 76 | builddir=$optarg 77 | ;; 78 | --prefix=*) 79 | append_cache_entry CMAKE_INSTALL_PREFIX PATH $optarg 80 | ;; 81 | --libdir=*) 82 | append_cache_entry CMAKE_INSTALL_LIBDIR PATH $optarg 83 | ;; 84 | --enable-debug) 85 | append_cache_entry ENABLE_DEBUG BOOL true 86 | ;; 87 | --enable-static) 88 | append_cache_entry ENABLE_STATIC BOOL true 89 | ;; 90 | --enable-static-only) 91 | append_cache_entry ENABLE_STATIC_ONLY BOOL true 92 | ;; 93 | --with-openssl=*) 94 | append_cache_entry OPENSSL_ROOT_DIR PATH $optarg 95 | ;; 96 | --with-bind=*) 97 | append_cache_entry BIND_ROOT_DIR PATH $optarg 98 | ;; 99 | --with-pcap=*) 100 | append_cache_entry PCAP_ROOT_DIR PATH $optarg 101 | ;; 102 | --with-flex=*) 103 | append_cache_entry FLEX_EXECUTABLE PATH $optarg 104 | ;; 105 | --with-bison=*) 106 | append_cache_entry BISON_EXECUTABLE PATH $optarg 107 | ;; 108 | *) 109 | echo "Invalid option '$1'. Try $0 --help to see available options." 110 | exit 1 111 | ;; 112 | esac 113 | shift 114 | done 115 | 116 | if [ -d $builddir ]; then 117 | # If build directory exists, check if it has a CMake cache 118 | if [ -f $builddir/CMakeCache.txt ]; then 119 | # If the CMake cache exists, delete it so that this configuration 120 | # is not tainted by a previous one 121 | rm -f $builddir/CMakeCache.txt 122 | fi 123 | else 124 | # Create build directory 125 | mkdir -p $builddir 126 | fi 127 | 128 | echo "Build Directory : $builddir" 129 | echo "Source Directory: $sourcedir" 130 | cd $builddir 131 | cmake $CMakeCacheEntries $sourcedir 132 | 133 | echo "# This is the command used to configure this build" >config.status 134 | echo $command >>config.status 135 | chmod u+x config.status 136 | -------------------------------------------------------------------------------- /src/pac_decl.cc: -------------------------------------------------------------------------------- 1 | #include "pac_decl.h" 2 | 3 | #include "pac_attr.h" 4 | #include "pac_context.h" 5 | #include "pac_dataptr.h" 6 | #include "pac_embedded.h" 7 | #include "pac_exception.h" 8 | #include "pac_expr.h" 9 | #include "pac_exttype.h" 10 | #include "pac_id.h" 11 | #include "pac_output.h" 12 | #include "pac_param.h" 13 | #include "pac_record.h" 14 | #include "pac_type.h" 15 | #include "pac_utils.h" 16 | 17 | DeclList* Decl::decl_list_ = nullptr; 18 | Decl::DeclMap Decl::decl_map_; 19 | 20 | Decl::Decl(ID* id, DeclType decl_type) : id_(id), decl_type_(decl_type), attrlist_(nullptr) { 21 | decl_map_[id_] = this; 22 | if ( ! decl_list_ ) 23 | decl_list_ = new DeclList(); 24 | decl_list_->push_back(this); 25 | 26 | DEBUG_MSG("Finished Decl %s\n", id_->Name()); 27 | 28 | analyzer_context_ = nullptr; 29 | } 30 | 31 | Decl::~Decl() { 32 | delete id_; 33 | delete_list(AttrList, attrlist_); 34 | } 35 | 36 | void Decl::AddAttrs(AttrList* attrs) { 37 | if ( ! attrs ) 38 | return; 39 | if ( ! attrlist_ ) 40 | attrlist_ = new AttrList(); 41 | foreach (i, AttrList, attrs) { 42 | attrlist_->push_back(*i); 43 | ProcessAttr(*i); 44 | } 45 | } 46 | 47 | void Decl::ProcessAttr(Attr* attr) { throw Exception(attr, "unhandled attribute"); } 48 | 49 | void Decl::SetAnalyzerContext() { 50 | analyzer_context_ = AnalyzerContextDecl::current_analyzer_context(); 51 | if ( ! analyzer_context_ ) { 52 | throw Exception(this, "analyzer context not defined"); 53 | } 54 | } 55 | 56 | void Decl::ProcessDecls(Output* out_h, Output* out_cc) { 57 | if ( ! decl_list_ ) 58 | return; 59 | 60 | foreach (i, DeclList, decl_list_) { 61 | Decl* decl = *i; 62 | current_decl_id = decl->id(); 63 | decl->Prepare(); 64 | } 65 | 66 | foreach (i, DeclList, decl_list_) { 67 | Decl* decl = *i; 68 | current_decl_id = decl->id(); 69 | decl->GenExternDeclaration(out_h); 70 | } 71 | 72 | out_h->println("namespace binpac {\n"); 73 | out_cc->println("namespace binpac {\n"); 74 | 75 | AnalyzerContextDecl* analyzer_context = AnalyzerContextDecl::current_analyzer_context(); 76 | 77 | foreach (i, DeclList, decl_list_) { 78 | Decl* decl = *i; 79 | current_decl_id = decl->id(); 80 | decl->GenForwardDeclaration(out_h); 81 | } 82 | 83 | if ( analyzer_context ) 84 | analyzer_context->GenNamespaceEnd(out_h); 85 | 86 | out_h->println(""); 87 | 88 | foreach (i, DeclList, decl_list_) { 89 | Decl* decl = *i; 90 | current_decl_id = decl->id(); 91 | decl->GenCode(out_h, out_cc); 92 | } 93 | 94 | if ( analyzer_context ) { 95 | analyzer_context->GenNamespaceEnd(out_h); 96 | analyzer_context->GenNamespaceEnd(out_cc); 97 | } 98 | 99 | out_h->println("} // namespace binpac"); 100 | out_cc->println("} // namespace binpac"); 101 | } 102 | 103 | Decl* Decl::LookUpDecl(const ID* id) { 104 | DeclMap::iterator it = decl_map_.find(id); 105 | if ( it == decl_map_.end() ) 106 | return nullptr; 107 | return it->second; 108 | } 109 | 110 | int HelperDecl::helper_id_seq = 0; 111 | 112 | HelperDecl::HelperDecl(HelperType helper_type, ID* context_id, EmbeddedCode* code) 113 | : Decl(new ID(strfmt("helper_%d", ++helper_id_seq)), HELPER), 114 | helper_type_(helper_type), 115 | context_id_(context_id), 116 | code_(code) {} 117 | 118 | HelperDecl::~HelperDecl() { 119 | delete context_id_; 120 | delete code_; 121 | } 122 | 123 | void HelperDecl::Prepare() { 124 | // Do nothing 125 | } 126 | 127 | void HelperDecl::GenExternDeclaration(Output* out_h) { 128 | if ( helper_type_ == EXTERN ) 129 | code_->GenCode(out_h, global_env()); 130 | } 131 | 132 | void HelperDecl::GenCode(Output* out_h, Output* out_cc) { 133 | Env* env = global_env(); 134 | 135 | #if 0 136 | if ( context_id_ ) 137 | { 138 | Decl *decl = Decl::LookUpDecl(context_id_); 139 | if ( ! decl ) 140 | { 141 | throw Exception(context_id_, 142 | fmt("cannot find declaration for %s", 143 | context_id_->Name())); 144 | } 145 | env = decl->env(); 146 | if ( ! env ) 147 | { 148 | throw Exception(context_id_, 149 | fmt("not a type or analyzer: %s", 150 | context_id_->Name())); 151 | } 152 | } 153 | #endif 154 | 155 | if ( helper_type_ == HEADER ) 156 | code_->GenCode(out_h, env); 157 | else if ( helper_type_ == CODE ) 158 | code_->GenCode(out_cc, env); 159 | else if ( helper_type_ == EXTERN ) 160 | ; // do nothing 161 | else 162 | ASSERT(0); 163 | } 164 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2020-2023 by the Zeek Project. See LICENSE for details. 2 | 3 | --- 4 | Language: Cpp 5 | AccessModifierOffset: -4 6 | AlignAfterOpenBracket: Align 7 | AlignConsecutiveAssignments: false 8 | AlignConsecutiveDeclarations: false 9 | AlignEscapedNewlines: Right 10 | AlignOperands: true 11 | AlignTrailingComments: true 12 | AllowAllParametersOfDeclarationOnNextLine: false 13 | AllowShortBlocksOnASingleLine: false 14 | AllowShortCaseLabelsOnASingleLine: true 15 | AllowShortFunctionsOnASingleLine: true 16 | AllowShortIfStatementsOnASingleLine: false 17 | AllowShortLoopsOnASingleLine: false 18 | AlwaysBreakAfterDefinitionReturnType: None 19 | AlwaysBreakAfterReturnType: None 20 | AlwaysBreakBeforeMultilineStrings: true 21 | AlwaysBreakTemplateDeclarations: Yes 22 | BinPackArguments: true 23 | BinPackParameters: true 24 | BraceWrapping: 25 | AfterClass: false 26 | AfterControlStatement: false 27 | AfterEnum: false 28 | AfterFunction: false 29 | AfterNamespace: false 30 | AfterObjCDeclaration: false 31 | AfterStruct: false 32 | AfterUnion: false 33 | AfterExternBlock: false 34 | BeforeCatch: false 35 | BeforeElse: true 36 | IndentBraces: false 37 | SplitEmptyFunction: false 38 | SplitEmptyRecord: false 39 | SplitEmptyNamespace: false 40 | BreakBeforeBinaryOperators: None 41 | BreakBeforeBraces: Custom 42 | BreakBeforeInheritanceComma: false 43 | BreakInheritanceList: BeforeColon 44 | BreakBeforeTernaryOperators: false 45 | BreakConstructorInitializersBeforeComma: false 46 | BreakConstructorInitializers: BeforeColon 47 | BreakAfterJavaFieldAnnotations: false 48 | BreakStringLiterals: true 49 | ColumnLimit: 120 50 | CommentPragmas: 'NOLINT' 51 | CompactNamespaces: false 52 | ConstructorInitializerAllOnOneLineOrOnePerLine: true 53 | ConstructorInitializerIndentWidth: 4 54 | ContinuationIndentWidth: 4 55 | Cpp11BracedListStyle: true 56 | DerivePointerAlignment: false 57 | DisableFormat: false 58 | ExperimentalAutoDetectBinPacking: false 59 | FixNamespaceComments: true 60 | ForEachMacros: 61 | - foreach 62 | - Q_FOREACH 63 | - BOOST_FOREACH 64 | IncludeBlocks: Regroup 65 | 66 | # Include categories go like this: 67 | # 0: reserved, since this automatically is the primary header for any .cc file 68 | # 1: zeek-config.h 69 | # 2: any c-style header 70 | # 3: any c++-style header 71 | # 4: any header that starts with "zeek/" 72 | # 5: everything else, which should catch any of the auto-generated code from the 73 | # build directory as well 74 | # 75 | # Sections 0-1 and 2-3 get grouped together in their respective blocks 76 | IncludeCategories: 77 | - Regex: '^"zeek-config\.h"' 78 | Priority: 1 79 | SortPriority: 1 80 | - Regex: '^"zeek/zeek-config\.h"' 81 | Priority: 1 82 | SortPriority: 2 83 | - Regex: '^<[[:print:]]+\.(h|hh)>' 84 | Priority: 2 85 | SortPriority: 2 86 | - Regex: '^<[[:print:]]+>' 87 | Priority: 2 88 | SortPriority: 3 89 | - Regex: '^"zeek/' 90 | Priority: 4 91 | - Regex: '.*' 92 | Priority: 5 93 | 94 | IncludeIsMainRegex: '$' 95 | IndentCaseLabels: true 96 | IndentPPDirectives: None 97 | IndentWidth: 4 98 | IndentWrappedFunctionNames: false 99 | JavaScriptQuotes: Leave 100 | JavaScriptWrapImports: true 101 | KeepEmptyLinesAtTheStartOfBlocks: false 102 | MacroBlockBegin: '^BEGIN_' 103 | MacroBlockEnd: '^END_' 104 | MaxEmptyLinesToKeep: 2 105 | NamespaceIndentation: None 106 | ObjCBinPackProtocolList: Auto 107 | ObjCBlockIndentWidth: 2 108 | ObjCSpaceAfterProperty: false 109 | ObjCSpaceBeforeProtocolList: true 110 | PenaltyBreakAssignment: 2 111 | PenaltyBreakBeforeFirstCallParameter: 500 112 | PenaltyBreakComment: 300 113 | PenaltyBreakFirstLessLess: 120 114 | PenaltyBreakString: 1000 115 | PenaltyBreakTemplateDeclaration: 10 116 | PenaltyExcessCharacter: 1000000 117 | PenaltyReturnTypeOnItsOwnLine: 1000 118 | PointerAlignment: Left 119 | ReflowComments: true 120 | SortIncludes: true 121 | SortUsingDeclarations: true 122 | SpaceAfterCStyleCast: false 123 | SpaceAfterTemplateKeyword: false 124 | SpaceAfterLogicalNot: true 125 | SpaceBeforeAssignmentOperators: true 126 | SpaceBeforeCpp11BracedList: false 127 | SpaceBeforeCtorInitializerColon: true 128 | SpaceBeforeInheritanceColon: true 129 | SpaceBeforeParens: ControlStatements 130 | SpaceBeforeRangeBasedForLoopColon: true 131 | SpaceInEmptyParentheses: false 132 | SpacesBeforeTrailingComments: 1 133 | SpacesInAngles: false 134 | SpacesInContainerLiterals: true 135 | SpacesInCStyleCastParentheses: false 136 | SpacesInParentheses: false 137 | SpacesInSquareBrackets: false 138 | SpacesInConditionalStatement: true 139 | Standard: Cpp11 140 | StatementMacros: 141 | - STANDARD_OPERATOR_1 142 | TabWidth: 4 143 | UseTab: Never 144 | --- 145 | Language: Json 146 | ... 147 | -------------------------------------------------------------------------------- /src/pac_expr.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_expr_h 2 | #define pac_expr_h 3 | 4 | #include 5 | 6 | #include "pac_common.h" 7 | #include "pac_datadep.h" 8 | 9 | class CaseExpr; 10 | 11 | class Expr : public Object, public DataDepElement { 12 | public: 13 | enum ExprType : uint8_t { 14 | #define EXPR_DEF(type, x, y) type, 15 | #include "pac_expr.def" 16 | #undef EXPR_DEF 17 | }; 18 | 19 | void init(); 20 | 21 | Expr(ID* id); 22 | Expr(Number* num); 23 | Expr(Nullptr* nullp); 24 | Expr(ConstString* s); 25 | Expr(RegEx* regex); 26 | Expr(ExprList* args); // for EXPR_CALLARGS 27 | Expr(Expr* index, CaseExprList* cases); 28 | 29 | Expr(ExprType type, Expr* op1); 30 | Expr(ExprType type, Expr* op1, Expr* op2); 31 | Expr(ExprType type, Expr* op1, Expr* op2, Expr* op3); 32 | 33 | ~Expr() override; 34 | 35 | const char* orig() const { return orig_.c_str(); } 36 | const ID* id() const { return id_; } 37 | const char* str() const { return str_.c_str(); } 38 | ExprType expr_type() const { return expr_type_; } 39 | 40 | void AddCaseExpr(CaseExpr* case_expr); 41 | 42 | // Returns the data "type" of the expression. Here we only 43 | // do a serious job for the EXPR_MEMBER and EXPR_SUBSCRIPT 44 | // operators. For arithmetic operations, we fall back 45 | // to "int". 46 | Type* DataType(Env* env) const; 47 | string DataTypeStr(Env* env) const; 48 | 49 | // Note: EvalExpr() may generate C++ statements in order to evaluate 50 | // variables in the expression, so the following is wrong: 51 | // 52 | // out->print("int x = "); 53 | // out->println("%s", expr->EvalExpr(out, env)); 54 | // 55 | // While putting them together is right: 56 | // 57 | // out->println("int x = %s", expr->EvalExpr(out, env)); 58 | // 59 | const char* EvalExpr(Output* out, Env* env); 60 | 61 | // force evaluation of IDs contained in this expression; 62 | // necessary with case expr and conditional let fields (&if) 63 | // for correct parsing of fields 64 | void ForceIDEval(Output* out_cc, Env* env); 65 | 66 | // Returns the set_* function of the expression. 67 | // The expression must be of form ID or x.ID. 68 | string SetFunc(Output* out, Env* env); 69 | 70 | // Returns true if the expression folds to an integer 71 | // constant with env, and puts the constant in *pn. 72 | // 73 | bool ConstFold(Env* env, int* pn) const; 74 | 75 | // Whether id is referenced in the expression 76 | bool HasReference(const ID* id) const; 77 | 78 | // Suppose the data for type might be incomplete, what is 79 | // the minimal number of bytes from data head required to 80 | // compute the expression? For example, how many bytes of frame 81 | // header do we need to determine the length of the frame? 82 | // 83 | // The parameter points to the Env of a type. 84 | // 85 | // Returns -1 if the number is not a constant. 86 | // 87 | int MinimalHeaderSize(Env* env); 88 | 89 | // Whether evaluation of the expression requires the analyzer context 90 | bool RequiresAnalyzerContext() const; 91 | 92 | protected: 93 | bool DoTraverse(DataDepVisitor* visitor) override; 94 | 95 | private: 96 | ExprType expr_type_; 97 | 98 | int num_operands_ = 0; 99 | Expr* operand_[3] = {nullptr}; 100 | 101 | ID* id_ = nullptr; // EXPR_ID 102 | Number* num_ = nullptr; // EXPR_NUM 103 | ConstString* cstr_ = nullptr; // EXPR_CSTR 104 | RegEx* regex_ = nullptr; // EXPR_REGEX 105 | ExprList* args_ = nullptr; // EXPR_CALLARGS 106 | CaseExprList* cases_ = nullptr; // EXPR_CASE 107 | Nullptr* nullp_ = nullptr; // EXPR_NULLPTR 108 | 109 | string str_; // value string 110 | string orig_; // original string for debugging info 111 | 112 | void GenStrFromFormat(Env* env); 113 | void GenEval(Output* out, Env* env); 114 | void GenCaseEval(Output* out_cc, Env* env); 115 | }; 116 | 117 | string OrigExprList(ExprList* exprlist); 118 | string EvalExprList(ExprList* exprlist, Output* out, Env* env); 119 | 120 | // An entry of the case expression, consisting of one or more constant 121 | // expressions for the case index and a value expression. 122 | class CaseExpr : public Object, public DataDepElement { 123 | public: 124 | CaseExpr(ExprList* index, Expr* value); 125 | ~CaseExpr() override; 126 | 127 | ExprList* index() const { return index_; } 128 | Expr* value() const { return value_; } 129 | 130 | bool HasReference(const ID* id) const; 131 | bool RequiresAnalyzerContext() const; 132 | 133 | protected: 134 | bool DoTraverse(DataDepVisitor* visitor) override; 135 | 136 | private: 137 | ExprList* index_; 138 | Expr* value_; 139 | }; 140 | 141 | #endif // pac_expr_h 142 | -------------------------------------------------------------------------------- /src/pac_analyzer.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_analyzer_h 2 | #define pac_analyzer_h 3 | 4 | #include "pac_common.h" 5 | #include "pac_field.h" 6 | #include "pac_typedecl.h" 7 | 8 | class AnalyzerElement; 9 | class AnalyzerState; 10 | class AnalyzerAction; // defined in pac_action.h 11 | class AnalyzerHelper; 12 | class AnalyzerFlow; 13 | class AnalyzerDataUnit; 14 | class AnalyzerFunction; 15 | class ConnDecl; 16 | class FlowDecl; 17 | typedef vector AnalyzerHelperList; 18 | typedef vector FunctionList; 19 | 20 | class AnalyzerDecl : public TypeDecl { 21 | public: 22 | AnalyzerDecl(ID* id, DeclType decl_type, ParamList* params); 23 | ~AnalyzerDecl() override; 24 | 25 | void AddElements(AnalyzerElementList* elemlist); 26 | 27 | void Prepare() override; 28 | void GenForwardDeclaration(Output* out_h) override; 29 | // void GenCode(Output *out_h, Output *out_cc); 30 | 31 | void GenInitCode(Output* out_cc) override; 32 | void GenCleanUpCode(Output* out_cc) override; 33 | 34 | string class_name() const; 35 | // string cookie_name() const; 36 | 37 | protected: 38 | virtual void ProcessFlowElement(AnalyzerFlow* flow_elem) = 0; 39 | virtual void ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) = 0; 40 | 41 | // Generate public/private declarations for member functions and 42 | // variables 43 | void GenPubDecls(Output* out_h, Output* out_cc) override; 44 | void GenPrivDecls(Output* out_h, Output* out_cc) override; 45 | 46 | // Generate the NewData() function 47 | virtual void GenProcessFunc(Output* out_h, Output* out_cc) = 0; 48 | 49 | // Generate the NewGap() function 50 | virtual void GenGapFunc(Output* out_h, Output* out_cc) = 0; 51 | 52 | // Generate the FlowEOF() function 53 | virtual void GenEOFFunc(Output* out_h, Output* out_cc) = 0; 54 | 55 | // Generate the functions 56 | void GenFunctions(Output* out_h, Output* out_cc); 57 | 58 | // Generate the action functions 59 | void GenActions(Output* out_h, Output* out_cc); 60 | 61 | // Generate the helper code segments 62 | void GenHelpers(Output* out_h, Output* out_cc); 63 | 64 | // Generate declarations for state variables and their set functions 65 | void GenStateVarDecls(Output* out_h); 66 | void GenStateVarSetFunctions(Output* out_h); 67 | 68 | // Generate code for initializing and cleaning up (including 69 | // memory de-allocating) state variables 70 | void GenStateVarInitCode(Output* out_cc); 71 | void GenStateVarCleanUpCode(Output* out_cc); 72 | 73 | StateVarList* statevars_; 74 | AnalyzerActionList* actions_; 75 | AnalyzerHelperList* helpers_; 76 | FunctionList* functions_; 77 | 78 | AnalyzerHelperList* constructor_helpers_; 79 | AnalyzerHelperList* destructor_helpers_; 80 | AnalyzerHelperList* eof_helpers_; 81 | }; 82 | 83 | class AnalyzerElement : public Object { 84 | public: 85 | enum ElementType { STATE, ACTION, FUNCTION, HELPER, FLOW, DATAUNIT }; 86 | AnalyzerElement(ElementType type) : type_(type) {} 87 | virtual ~AnalyzerElement() {} 88 | 89 | ElementType type() const { return type_; } 90 | 91 | private: 92 | ElementType type_; 93 | }; 94 | 95 | // A collection of variables representing analyzer states. 96 | class AnalyzerState : public AnalyzerElement { 97 | public: 98 | AnalyzerState(StateVarList* statevars) : AnalyzerElement(STATE), statevars_(statevars) {} 99 | ~AnalyzerState() override; 100 | 101 | StateVarList* statevars() const { return statevars_; } 102 | 103 | private: 104 | StateVarList* statevars_; 105 | }; 106 | 107 | // A collection of embedded C++ code 108 | class AnalyzerHelper : public AnalyzerElement { 109 | public: 110 | enum Type { 111 | MEMBER_DECLS, 112 | INIT_CODE, 113 | CLEANUP_CODE, 114 | EOF_CODE, 115 | }; 116 | AnalyzerHelper(Type helper_type, EmbeddedCode* code) 117 | : AnalyzerElement(HELPER), helper_type_(helper_type), code_(code) {} 118 | ~AnalyzerHelper() override; 119 | 120 | Type helper_type() const { return helper_type_; } 121 | 122 | void GenCode(Output* out_h, Output* out_cc, AnalyzerDecl* decl); 123 | 124 | EmbeddedCode* code() const { return code_; } 125 | 126 | private: 127 | Type helper_type_; 128 | EmbeddedCode* code_; 129 | }; 130 | 131 | // The type and parameters of (uni-directional) flows of a connection. 132 | 133 | class FlowField : public Field { 134 | public: 135 | FlowField(ID* flow_id, ParameterizedType* flow_type); 136 | void GenInitCode(Output* out, Env* env) override; 137 | }; 138 | 139 | class AnalyzerFlow : public AnalyzerElement { 140 | public: 141 | enum Direction { UP, DOWN }; 142 | AnalyzerFlow(Direction dir, ID* type_id, ExprList* params); 143 | ~AnalyzerFlow() override; 144 | 145 | Direction dir() const { return dir_; } 146 | FlowField* flow_field() const { return flow_field_; } 147 | 148 | FlowDecl* flow_decl(); 149 | 150 | private: 151 | Direction dir_; 152 | ID* type_id_; 153 | FlowField* flow_field_; 154 | FlowDecl* flow_decl_; 155 | }; 156 | 157 | #endif // pac_analyzer_h 158 | -------------------------------------------------------------------------------- /lib/binpac_buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef binpac_buffer_h 2 | #define binpac_buffer_h 3 | 4 | #include 5 | 6 | #include "binpac.h" 7 | 8 | namespace binpac { 9 | 10 | class FlowBuffer { 11 | public: 12 | struct Policy { 13 | int max_capacity; 14 | int min_capacity; 15 | int contract_threshold; 16 | }; 17 | 18 | enum LineBreakStyle { 19 | CR_OR_LF, // CR or LF or CRLF 20 | STRICT_CRLF, // CR followed by LF 21 | CR_LF_NUL, // CR or LF or CR-LF or CR-NUL 22 | LINE_BREAKER, // User specified linebreaker 23 | }; 24 | 25 | FlowBuffer(LineBreakStyle linebreak_style = CR_OR_LF); 26 | virtual ~FlowBuffer(); 27 | 28 | void NewData(const_byteptr begin, const_byteptr end); 29 | void NewGap(int length); 30 | 31 | // Interface for delayed parsing. Sometimes BinPAC doesn't get the 32 | // buffering right and then one can use these to feed parts 33 | // individually and assemble them internally. After calling 34 | // FinishBuffer(), one can send the upper-layer flow an FlowEOF() to 35 | // trigger parsing. 36 | void BufferData(const_byteptr data, const_byteptr end); 37 | void FinishBuffer(); 38 | 39 | // Discard unprocessed data 40 | void DiscardData(); 41 | 42 | // Whether there is enough data for the frame 43 | bool ready() const { return message_complete_ || mode_ == UNKNOWN_MODE; } 44 | 45 | inline const_byteptr begin() const { 46 | BINPAC_ASSERT(ready()); 47 | return (buffer_n_ == 0) ? orig_data_begin_ : buffer_; 48 | } 49 | 50 | inline const_byteptr end() const { 51 | BINPAC_ASSERT(ready()); 52 | if ( buffer_n_ == 0 ) { 53 | BINPAC_ASSERT(frame_length_ >= 0); 54 | const_byteptr end = orig_data_begin_ + frame_length_; 55 | BINPAC_ASSERT(end <= orig_data_end_); 56 | return end; 57 | } 58 | else 59 | return buffer_ + buffer_n_; 60 | } 61 | 62 | inline int data_length() const { 63 | if ( buffer_n_ > 0 ) 64 | return buffer_n_; 65 | 66 | if ( frame_length_ < 0 || orig_data_begin_ + frame_length_ > orig_data_end_ ) 67 | return orig_data_end_ - orig_data_begin_; 68 | else 69 | return frame_length_; 70 | } 71 | 72 | inline bool data_available() const { return buffer_n_ > 0 || orig_data_end_ > orig_data_begin_; } 73 | 74 | void SetLineBreaker(unsigned char* lbreaker); 75 | void UnsetLineBreaker(); 76 | void NewLine(); 77 | // A negative frame_length represents a frame till EOF 78 | void NewFrame(int frame_length, bool chunked_); 79 | void GrowFrame(int new_frame_length); 80 | 81 | int data_seq() const { 82 | int data_seq_at_orig_data_begin = data_seq_at_orig_data_end_ - (orig_data_end_ - orig_data_begin_); 83 | if ( buffer_n_ > 0 ) 84 | return data_seq_at_orig_data_begin; 85 | else 86 | return data_seq_at_orig_data_begin + data_length(); 87 | } 88 | bool eof() const { return eof_; } 89 | void set_eof(); 90 | 91 | bool have_pending_request() const { return have_pending_request_; } 92 | 93 | static void init(Policy p) { policy = p; } 94 | 95 | protected: 96 | // Reset the buffer for a new message 97 | void NewMessage(); 98 | 99 | void ClearPreviousData(); 100 | 101 | // Expand the buffer to at least bytes. If there 102 | // are contents in the existing buffer, copy them to the new 103 | // buffer. 104 | void ExpandBuffer(int length); 105 | 106 | // Contract the buffer to some minimum capacity. 107 | // Existing contents in the buffer are preserved (but only usage 108 | // at the time of creation this function is when the contents 109 | // are being discarded due to parsing exception or have already been 110 | // copied out after parsing a complete unit). 111 | void ContractBuffer(); 112 | 113 | // Reset line state when transit from frame mode to line mode. 114 | void ResetLineState(); 115 | 116 | void AppendToBuffer(const_byteptr data, int len); 117 | 118 | // MarkOrCopy{Line,Frame} sets message_complete_ and 119 | // marks begin/end pointers if a line/frame is complete, 120 | // otherwise it clears message_complete_ and copies all 121 | // the original data to the buffer. 122 | // 123 | void MarkOrCopy(); 124 | void MarkOrCopyLine(); 125 | void MarkOrCopyFrame(); 126 | 127 | void MarkOrCopyLine_CR_OR_LF(); 128 | void MarkOrCopyLine_STRICT_CRLF(); 129 | void MarkOrCopyLine_LINEBREAK(); 130 | 131 | int buffer_n_; // number of bytes in the buffer 132 | int buffer_length_; // size of the buffer 133 | unsigned char* buffer_; 134 | bool message_complete_; 135 | int frame_length_; 136 | bool chunked_; 137 | const_byteptr orig_data_begin_, orig_data_end_; 138 | 139 | LineBreakStyle linebreak_style_; 140 | LineBreakStyle linebreak_style_default; 141 | unsigned char linebreaker_; 142 | 143 | enum { 144 | UNKNOWN_MODE, 145 | LINE_MODE, 146 | FRAME_MODE, 147 | } mode_; 148 | 149 | enum { 150 | CR_OR_LF_0, 151 | CR_OR_LF_1, 152 | STRICT_CRLF_0, 153 | STRICT_CRLF_1, 154 | FRAME_0, 155 | } state_; 156 | 157 | int data_seq_at_orig_data_end_; 158 | bool eof_; 159 | bool have_pending_request_; 160 | 161 | static Policy policy; 162 | }; 163 | 164 | typedef FlowBuffer* flow_buffer_t; 165 | 166 | } // namespace binpac 167 | 168 | #endif // binpac_buffer_h 169 | -------------------------------------------------------------------------------- /src/pac_record.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_record_h 2 | #define pac_record_h 3 | 4 | #include "pac_common.h" 5 | #include "pac_field.h" 6 | #include "pac_id.h" 7 | #include "pac_let.h" 8 | #include "pac_type.h" 9 | 10 | class RecordType : public Type { 11 | public: 12 | RecordType(RecordFieldList* fields); 13 | ~RecordType() override; 14 | 15 | bool DefineValueVar() const override; 16 | string DataTypeStr() const override; 17 | 18 | void Prepare(Env* env, int flags) override; 19 | 20 | void GenPubDecls(Output* out, Env* env) override; 21 | void GenPrivDecls(Output* out, Env* env) override; 22 | 23 | void GenInitCode(Output* out, Env* env) override; 24 | void GenCleanUpCode(Output* out, Env* env) override; 25 | 26 | int StaticSize(Env* env) const override; 27 | 28 | void SetBoundaryChecked() override; 29 | 30 | const ID* parsing_dataptr_var() const; 31 | 32 | bool IsPointerType() const override { 33 | ASSERT(0); 34 | return false; 35 | } 36 | 37 | protected: 38 | void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; 39 | void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; 40 | 41 | Type* DoClone() const override { return nullptr; } 42 | 43 | void DoMarkIncrementalInput() override; 44 | 45 | bool DoTraverse(DataDepVisitor* visitor) override; 46 | bool ByteOrderSensitive() const override; 47 | 48 | private: 49 | Field* parsing_dataptr_var_field_; 50 | RecordFieldList* record_fields_; 51 | }; 52 | 53 | // A data field of a record type. A RecordField corresponds to a 54 | // segment of input data, and therefore RecordField's are ordered---each 55 | // of them has a known previous and next field. 56 | 57 | class RecordField : public Field { 58 | public: 59 | RecordField(FieldType tof, ID* id, Type* type); 60 | ~RecordField() override; 61 | 62 | RecordType* record_type() const { return record_type_; } 63 | void set_record_type(RecordType* ty) { record_type_ = ty; } 64 | 65 | virtual void GenParseCode(Output* out, Env* env) = 0; 66 | 67 | RecordField* prev() const { return prev_; } 68 | RecordField* next() const { return next_; } 69 | void set_prev(RecordField* f) { prev_ = f; } 70 | void set_next(RecordField* f) { next_ = f; } 71 | 72 | int static_offset() const { return static_offset_; } 73 | void set_static_offset(int offset) { static_offset_ = offset; } 74 | 75 | int parsing_state_seq() const { return parsing_state_seq_; } 76 | void set_parsing_state_seq(int x) { parsing_state_seq_ = x; } 77 | 78 | virtual int StaticSize(Env* env, int offset) const = 0; 79 | const char* FieldSize(Output* out, Env* env); 80 | const char* FieldOffset(Output* out, Env* env); 81 | 82 | virtual bool BoundaryChecked() const { return boundary_checked_; } 83 | virtual void SetBoundaryChecked() { boundary_checked_ = true; } 84 | 85 | virtual bool RequiresByteOrder() const = 0; 86 | 87 | friend class RecordType; 88 | 89 | protected: 90 | RecordType* record_type_; 91 | RecordField* prev_; 92 | RecordField* next_; 93 | bool boundary_checked_; 94 | int static_offset_; 95 | int parsing_state_seq_; 96 | 97 | DataPtr* begin_of_field_dataptr; 98 | DataPtr* end_of_field_dataptr; 99 | char* field_size_expr; 100 | char* field_offset_expr; 101 | ID* end_of_field_dataptr_var; 102 | 103 | const DataPtr& getFieldBegin(Output* out_cc, Env* env); 104 | const DataPtr& getFieldEnd(Output* out_cc, Env* env); 105 | virtual void GenFieldEnd(Output* out, Env* env, const DataPtr& begin) = 0; 106 | 107 | bool AttemptBoundaryCheck(Output* out_cc, Env* env); 108 | virtual bool GenBoundaryCheck(Output* out_cc, Env* env) = 0; 109 | }; 110 | 111 | class RecordDataField : public RecordField, public Evaluatable { 112 | public: 113 | RecordDataField(ID* arg_id, Type* arg_type); 114 | ~RecordDataField() override; 115 | 116 | // Instantiates abstract class Field 117 | void Prepare(Env* env) override; 118 | void GenParseCode(Output* out, Env* env) override; 119 | 120 | // Instantiates abstract class Evaluatable 121 | void GenEval(Output* out, Env* env) override; 122 | 123 | int StaticSize(Env* env, int) const override { return type()->StaticSize(env); } 124 | 125 | void SetBoundaryChecked() override; 126 | 127 | bool RequiresByteOrder() const override { return type()->RequiresByteOrder(); } 128 | bool RequiresAnalyzerContext() const override; 129 | 130 | protected: 131 | void GenFieldEnd(Output* out, Env* env, const DataPtr& begin) override; 132 | bool GenBoundaryCheck(Output* out_cc, Env* env) override; 133 | bool DoTraverse(DataDepVisitor* visitor) override; 134 | }; 135 | 136 | enum PaddingType { PAD_BY_LENGTH, PAD_TO_OFFSET, PAD_TO_NEXT_WORD }; 137 | 138 | class RecordPaddingField : public RecordField { 139 | public: 140 | RecordPaddingField(ID* id, PaddingType ptype, Expr* expr); 141 | ~RecordPaddingField() override; 142 | 143 | void Prepare(Env* env) override; 144 | 145 | void GenPubDecls(Output* out, Env* env) override { /* nothing */ 146 | } 147 | void GenPrivDecls(Output* out, Env* env) override { /* nothing */ 148 | } 149 | 150 | void GenInitCode(Output* out, Env* env) override { /* nothing */ 151 | } 152 | void GenCleanUpCode(Output* out, Env* env) override { /* nothing */ 153 | } 154 | void GenParseCode(Output* out, Env* env) override; 155 | 156 | int StaticSize(Env* env, int offset) const override; 157 | 158 | bool RequiresByteOrder() const override { return false; } 159 | 160 | protected: 161 | void GenFieldEnd(Output* out, Env* env, const DataPtr& begin) override; 162 | bool GenBoundaryCheck(Output* out_cc, Env* env) override; 163 | bool DoTraverse(DataDepVisitor* visitor) override; 164 | 165 | private: 166 | PaddingType ptype_; 167 | Expr* expr_; 168 | int wordsize_; 169 | }; 170 | 171 | #endif // pac_record_h 172 | -------------------------------------------------------------------------------- /src/pac_id.h: -------------------------------------------------------------------------------- 1 | #ifndef pac_id_h 2 | #define pac_id_h 3 | 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | #include "pac_common.h" 9 | #include "pac_dbg.h" 10 | #include "pac_utils.h" 11 | 12 | // Classes handling identifiers. 13 | // 14 | // ID -- name and location of definition of an ID 15 | // 16 | // IDRecord -- association of an ID, its definition type (const, global, temp, 17 | // member, or union member), and its evaluation method. 18 | // 19 | // Evaluatable -- interface for a variable or a field that needs be evaluated 20 | // before referenced. 21 | // 22 | // Env -- a mapping from ID names to their L/R-value expressions and evaluation 23 | // methods. 24 | 25 | enum IDType { 26 | CONST, 27 | GLOBAL_VAR, 28 | TEMP_VAR, 29 | MEMBER_VAR, 30 | PRIV_MEMBER_VAR, 31 | UNION_VAR, 32 | STATE_VAR, 33 | MACRO, 34 | FUNC_ID, 35 | FUNC_PARAM, 36 | }; 37 | 38 | class ID; 39 | class IDRecord; 40 | class Env; 41 | class Evaluatable; 42 | 43 | class ID : public Object { 44 | public: 45 | ID(string arg_name) : name(arg_name), anonymous_id_(false) { locname = nfmt("%s:%s", Location(), Name()); } 46 | ~ID() { delete[] locname; } 47 | 48 | bool operator==(ID const& x) const { return name == x.Name(); } 49 | 50 | const char* Name() const { return name.c_str(); } 51 | const char* LocName() const { return locname; } 52 | bool is_anonymous() const { return anonymous_id_; } 53 | 54 | ID* clone() const { return new ID(Name()); } 55 | 56 | protected: 57 | string name; 58 | bool anonymous_id_; 59 | char* locname; 60 | friend class ID_ptr_cmp; 61 | 62 | public: 63 | static ID* NewAnonymousID(const string& prefix); 64 | 65 | private: 66 | static int anonymous_id_seq; 67 | }; 68 | 69 | // A comparison operator for pointers to ID's. 70 | class ID_ptr_cmp { 71 | public: 72 | bool operator()(const ID* const& id1, const ID* const& id2) const { 73 | ASSERT(id1); 74 | ASSERT(id2); 75 | return id1->name < id2->name; 76 | } 77 | }; 78 | 79 | class IDRecord { 80 | public: 81 | IDRecord(Env* env, const ID* id, IDType id_type); 82 | ~IDRecord(); 83 | 84 | IDType GetType() const { return id_type; } 85 | 86 | void SetDataType(Type* type) { data_type = type; } 87 | Type* GetDataType() const { return data_type; } 88 | 89 | void SetEvalMethod(Evaluatable* arg_eval) { eval = arg_eval; } 90 | void Evaluate(Output* out, Env* env); 91 | void SetEvaluated(bool v); 92 | bool Evaluated() const { return evaluated; } 93 | 94 | void SetField(Field* f) { field = f; } 95 | Field* GetField() const { return field; } 96 | 97 | void SetConstant(int c); 98 | bool GetConstant(int* pc) const; 99 | 100 | void SetMacro(Expr* expr); 101 | Expr* GetMacro() const; 102 | 103 | const char* RValue() const; 104 | const char* LValue() const; 105 | 106 | protected: 107 | Env* env; 108 | const ID* id; 109 | IDType id_type; 110 | 111 | string rvalue; 112 | string lvalue; 113 | string setfunc; 114 | 115 | Type* data_type; 116 | 117 | Field* field; 118 | 119 | int constant; 120 | bool constant_set; 121 | 122 | Expr* macro; 123 | 124 | bool evaluated; 125 | bool in_evaluation; // to detect cyclic dependence 126 | Evaluatable* eval; 127 | }; 128 | 129 | class Evaluatable { 130 | public: 131 | virtual ~Evaluatable() {} 132 | virtual void GenEval(Output* out, Env* env) = 0; 133 | }; 134 | 135 | class Env { 136 | public: 137 | Env(Env* parent_env, Object* context_object); 138 | ~Env(); 139 | 140 | bool allow_undefined_id() const { return allow_undefined_id_; } 141 | void set_allow_undefined_id(bool x) { allow_undefined_id_ = x; } 142 | 143 | bool in_branch() const { return in_branch_; } 144 | void set_in_branch(bool x) { in_branch_ = x; } 145 | 146 | void AddID(const ID* id, IDType id_type, Type* type); 147 | void AddConstID(const ID* id, const int c, Type* type = 0); 148 | void AddMacro(const ID* id, Expr* expr); 149 | 150 | // Generate a temp ID with a unique name 151 | ID* AddTempID(Type* type); 152 | 153 | IDType GetIDType(const ID* id) const; 154 | const char* RValue(const ID* id) const; 155 | const char* LValue(const ID* id) const; 156 | // const char *SetFunc(const ID *id) const; 157 | 158 | // Set evaluation method for the ID 159 | void SetEvalMethod(const ID* id, Evaluatable* eval); 160 | 161 | // Evaluate the ID according to the evaluation method. It 162 | // assumes the ID has an evaluation emthod. It does nothing 163 | // if the ID has already been evaluated. 164 | void Evaluate(Output* out, const ID* id); 165 | 166 | // Whether the ID has already been evaluated. 167 | bool Evaluated(const ID* id) const; 168 | 169 | // Set the ID as evaluated (or not). 170 | void SetEvaluated(const ID* id, bool v = true); 171 | 172 | void SetField(const ID* id, Field* field); 173 | Field* GetField(const ID* id) const; 174 | 175 | bool GetConstant(const ID* id, int* pc) const; 176 | 177 | Expr* GetMacro(const ID* id) const; 178 | 179 | Type* GetDataType(const ID* id) const; 180 | 181 | string DataTypeStr(const ID* id) const; 182 | 183 | protected: 184 | IDRecord* lookup(const ID* id, bool recursive, bool raise_exception) const; 185 | 186 | void SetDataType(const ID* id, Type* type); 187 | void SetConstant(const ID* id, int constant); 188 | void SetMacro(const ID* id, Expr* macro); 189 | 190 | private: 191 | Env* parent; 192 | Object* context_object_; 193 | typedef map id_map_t; 194 | id_map_t id_map; 195 | bool allow_undefined_id_; 196 | bool in_branch_; 197 | }; 198 | 199 | extern const ID* default_value_var; 200 | extern const ID* null_id; 201 | extern const ID* null_byteseg_id; 202 | extern const ID* begin_of_data; 203 | extern const ID* end_of_data; 204 | extern const ID* len_of_data; 205 | extern const ID* byteorder_id; 206 | extern const ID* bigendian_id; 207 | extern const ID* littleendian_id; 208 | extern const ID* unspecified_byteorder_id; 209 | extern const ID* analyzer_context_id; 210 | extern const ID* context_macro_id; 211 | extern const ID* this_id; 212 | extern const ID* sourcedata_id; 213 | // extern const ID *sourcedata_begin_id; 214 | // extern const ID *sourcedata_end_id; 215 | extern const ID* connection_id; 216 | extern const ID* upflow_id; 217 | extern const ID* downflow_id; 218 | extern const ID* dataunit_id; 219 | extern const ID* flow_buffer_id; 220 | extern const ID* element_macro_id; 221 | extern const ID* cxt_connection_id; 222 | extern const ID* cxt_flow_id; 223 | extern const ID* input_macro_id; 224 | extern const ID* parsing_state_id; 225 | extern const ID* buffering_state_id; 226 | 227 | extern void init_builtin_identifiers(); 228 | extern Env* global_env(); 229 | 230 | extern string set_function(const ID* id); 231 | 232 | #endif // pac_id_h 233 | --------------------------------------------------------------------------------