Xcode のファイル(Xobject) フォーマット
履歴:
Xcode は、C言語プログラムに復元可能な中間コードである。このコードレベ
ルでは、以下の特徴を持つ:
- C言語に復元可能な情報を保持する。
- C言語相当の型情報を表現できる。
- 様々な変形に必要な構文要素を持つ。
- human-readableなフォーマット。
- Xcode ファイル へは、Cプログラムに対して、C-frontにより変換する。
- Xcode ファイル から、Cプログラムに対して、C-frontにより変換する。
- exc java tool kitにより、X codeに対する解析、プログラムを作ること
ができる。
記法:
以下の記述では、BNFを用いる。
- 定義は、構文要素 := 構文要素 で表現する。
- 終端記号は、' 'で表現する。
- 複数の構文要素がある場合は、構文要素1 | 構文要素2 | ... のように
表現する。
- '[ ... ]' で囲まれる構文要素は省略可能な構文要素を表す。
- '{ ... }*' は、繰り返し可能な構文要素を表す。
- 各構文要素は、スペース、タブなど空白文字で、区切られているものと
する。
- Xcodeの表記については、簡単に (opcode ...)と記述する。
この場合、opcodeは大文字で記述し、小文字は非終端記号とみなす。
Xcode の テキスト表現
Xcode のexpressionは、tree構造をもつデータ構造を表現するためのもので、
テキスト形式では、以下のように表現される:
Xcode_expr :=
'(' opcode Xcode_expr* ')'
| Xcode_terminal_expr
Xcode_terminal_expr :=
'(' opcode number ')' /* for number */
| '(' opcode symbol ')' /* symbol */
| '(' opcode string ')' /* string */
| '(' opcode number number ')' /* double word */
opcode := code_name [':' data_type ['@'[file_name.]line_number]]
code_name := symbol
file_name := symbol
line_number := number
string := '"' ... '"'
- numberは、数字からなる文字列。0xから始まる場合は16進数。
- symbolは、英数字からなる文字列。
- stringは、'"'で囲まれた空白を含む文字列。
- opcodeは、exprcode.defにより定義された文字列。
- Xcodeの表記については、簡単に (opcode ...)と記述する。
この場合、opcodeは大文字で記述し、小文字は非終端記号とみなす。
それぞれの文が、どのように変換されるかについては、後述。
Xcode ファイル・トップレベル
ファイルは'%'でセパレートされた3つのセクションからなる:
xcode_file :=
type_table
'%'
global_id_table
'%'
global_decl_list
- '#' から、行末まではコメントとして解釈される。
- '/*' と '*/'で 囲む、Cスタイルのコメントを使うことできる。
type_table セクション
type_table セクションは、このファイル全体で使われているデータ型につい
てのテーブルである。プログラム中で参照されるデータ型を表現する
type_entryの並びである:
type_table := {type_entry}*
type_entry :=
pointer_type_entry
| function_type_entry
| array_type_entry
| structure_or_union_type_entry
| enum_type_entry
type_id タイプ識別子
type_idは、タイプの識別子である。基本データ型の他に、ポインタなど派生
するタイプに関しては、先頭の1文字が種別を表し、英数字からなる識別子を
付ける。
type_id :=
P_type_id /* 'P'+数字* からなる文字列 */
| F_type_id /* 'F'+数字* からなる文字列 */
| A_type_id /* 'A'+数字* からなる文字列 */
| SU_type_id /* 'S'or'U'+数字* からなる文字列 */
| E_type_id /* 'E'+数字* からなる文字列 */
| 'void'
| 'char'
| 'int'
| 'long'
| 'long_long'
| 'unsigned_char'
| 'unsigned_short'
| 'unsigned'
| 'unsigned_long'
| 'unsigned_long_long'
| 'float'
| 'double'
| 'long_double'
type_size := number
type_align := number
is_const := 0 | 1
is_volatile := 0 | 1
is_volatile := 0 | 1
type_entryの始めのtype_id type_size type_align is_const is_volatile
は共通である。それぞれ、このタイプの識別子、サイズ、アライメント、
constか、volatileかを示す。
ポインタ型 type_entry
ポインタ型は、ref_type_idで、参照するタイプを示す。
pointer_type_entry :=
'{' P_type_id type_size type_align is_const is_volatile
ref_type_id '}'
ref_type_id := type_id
例:"int *"に対応するtype_entryは以下のようになる。
{ P0123 4 4 0 0 int}
関数型 type_entry
関数型は、ref_type_idで関数の返す値のデータ型を指定する。
param_listで、引数の
(proto_typeはプロトタイプ宣言されているかどうか?)
function_type_entry :=
'{' F_type_id type_size type_align is_const is_volatile
ret_type_id is_proto param_list '}'
ret_type_id := type_id
is_proto := 0 | 1
param_list := (LIST (IDNET param_name1) (INDENT param_name2) ...)
例: "double foo(int a,int b)" のfooに対するデータ型は以下のようになる。
{F023 0 0 0 0 double 0 (LIST (IDENT a) (IDENT b))}
配列型 type_entry
配列型は、配列の要素のデータ型elem_type_idと配列の次元をn_dimを指定する。
なお、type_sizeは配列全体のサイズをバイト数で指定する。
array_type_entry :=
'{' A_type_id type_size type_align is_const is_volatile
elem_type_id n_dim '}'
elem_type_id := type_id
n_dim := number
例: "int a[10]"のaに対するtype_entryは以下のようになる。
{A011 0x28 0x4 0 0 int 0xa}
構造体型 type_entry
struct/unionの構造体データ型は、メンバーに対するシンボルテーブル
id_listを指定する。
struct_or_union_type_entry :=
'{' SU_type_id type_size type_align is_const is_volatile
member_id_list '}'
例: "struct {int x1; int y1;} S;"のSに対するtype_entryは以下のように
なる。
{S6e8e0 0x8 0x4 0 0 [x1 * int ()] [y1 * int ()] }
- type_sizeは配列全体のサイズをバイト数で指定する。
type_alignは、メンバ中の最大alignにする。
- シンボルテーブル中のstorage classは、'*'でなくては
ならない。シンボルテーブルについては後述。
- 構造体のタグ名がある場合には、スコープに対応するシンボルテーブル
に定義されている。
enum型 type_entry
enum型は、enumのメンバー識別子のリストを指定する。
enum_type_entry :=
'{' E_type_id type_size type_align is_const is_volatile
moe_list '}'
moe_list := (LIST (IDNET moe_name1) (INDENT moe_name2) ...)
例: "enum { e1,e2,e3 } ee; "のeeに対するtype_entryは以下のようになる。
{E6b510 0x4 0x4 0 0 (LIST (IDENT e1) (IDENT e2) (IDENT e3))}
-
- メンバの識別子は、スコープに対応するシンボルテーブルにクラスmoeと
して定義されている。
- enumのタグ名がある場合には、スコープに対応するシンボルテーブル
に定義されている。
global_id_table セクション
global_id_table セクションは、このファイルスコープにおいて、大域的に定
義されているシンボルの並びである。
global_id_table := id_list
id_list シンボルテーブル
id_listとは、シンボルテーブルを構成するid_entryの並びである。
シンボルテーブルは以下の場所に用いられる:
- global_id_table
- struct/unionのメンバー、
- 関数の引数リストに対するシンボルテーブル
- compound statementの中のシンボルテーブル
id_list := { id_entry }*
id_entry := '[' id_symbol storage_class type_id value_expr ['*'] ']'
storage_class :=
'*'
| 'auto'
| 'param'
| 'extern'
| 'extern_def'
| 'static'
| 'register'
| 'label'
| 'tagname'
| 'moe'
| 'typedef_name'
- id_symbolはシンボルの識別子
- type_idにおいて、シンボルのデータ型を指定する。
- storage_classは、シンボルの記憶クラスを指定する。
- value_exprは、識別子が変数などの場合、そのアドレスをXcode_exprで
指定する。
- '*' がある場合には、VAR_DECL/EXT_DECLされていないシンボル。
コンパイラで生成するシンボルに用いる。
例: "int xyz;"の変数xyzに対するシンボルテーブルエントリは以下のように
なる。なお、P6e7e0は "int *"に対するtype_id。
[xyz extern_def int (VAR_ADDR:P6e7e0 xyz)]
例: "int foo()"の関数fooに対するシンボルテーブルエントリは以下のよう
になる。なお、F6f168は、fooのデータ型に対するtype_id。P6f1a8は、F6f168
へのポインタのtype_id。識別子fooは関数へのポインタになることに注意。
[foo extern_def F6f168 (FUNC_ADDR:P6f1a8 foo)]
global_decl_list セクション
global_decl_listセクションは、プログラム中の宣言を集めたものである。
glboal_declのXcode expressionの並びになる。
global_decl_list := {global_decl}*
global_decl :=
(LIST global_decl ... )
| (FUNCTION_DEFINITION (IDENT func_name)
(ID_LIST [id_list]) (LIST [param_decl_list]) body)
| (EXT_DECL (IDENT var_name) ())
| (VAR_DECL (IDENT var_name) initializer)
param_decl_list := {(VAR_DECL (IDENT param_name) ())}*
body := statement
- FUNCTION_DEFINITIONは、関数本体の定義。id_listにおいて、パラメー
タに対するシンボルテーブルを指定する。id_list内のシンボルテーブルエン
トリは、引数の順序で並んでいなくてはならない。
- EXT_DECL、VAR_DECLはソースレベルの変数の宣言に対応する。
decompileにおいては、VAR_DECLに対しては対応する変数が、
EXT_DECLに関しては、"extern"記憶クラスで変数が宣言される。(検討事項)
- initializerは初期化データを記述するもので、構造体や配列の場合はそ
れに対応したリスト構造で記述された値を指定する。
Xcode Statement
Cプログラムの制御文の構文要素に対応する表現である。
statement :=
(EXPR_STATEMENT expr)
| (LIST statement1 statement2 ...)
| (COMPOUND_STATEMENT (ID_LIST [id_list]) (LIST [var_decls])
(LIST statement1 statement2 ....))
| (IF_STATEMENT cond_expr then_statement else_statement)
| (WHILE_STATEMENT cond_expr body_statement)
| (DO_STATEMENT body_statement cond_expr)
| (FOR_STATEMENT init_expr cond_expr iter_expr body_statement)
| (BREAK_STATEMENT)
| (CONTINUE_STATEMENT)
| (RETURN_STATEMENT return_expr)
| (GOTO_STATEMENT (IDENT label_symbol))
| (STATEMENT_LABEL (IDENT label_symbol))
| (SWITCH_STATEMENT switch_expr body_statement)
| (CASE_LABEL case_expr)
| (DEFAULT_LABEL)
| (OMP_PRAGMA (INT_CONSTANT omp_dir_id)
(LIST omp_clause1 omp_clause2 ...) body_statement)
- _exprは Xcode expressionを表す。
- _statement は、Xcode statementを表す。
- Xcode statementに関しては、Xcodeのtypeはない。
- line情報については省略。
- COMPOUND_STATMENTのID_LISTはこのcompound statment内でのスコープに
対応するシンボルテーブルを指定する。
Xcode Expression
Cの式の構文要素に対応する表現である。
それぞれのXcodeには、データ型が加えられており、式のデータ型情報を取り
出すことができる。
expression :=
primary_expr
| (unary_opcode operand_expr)
| (binary_opcode left_expr right_expr)
| (assign_binary_opcode left_expr right_expr)
| (binary_opcode left_expr right_expr)
| (logical_unary_opcode operand_expr)
| (logical_binary_opcode left_expr right_expr)
| (ASSIGN_EXPR left_expr right_expr)
| (COMMA_EXPR left_expr right_expr)
| (CONDITIONAL_EXPR cond_expr (LIST then_expr else_expr))
| (POST_INCR_EXPR operand_expr)
| (POST_DECR_EXPR operand_expr)
| (FUNCTION_CALL func_expr (LIST arg_expr1 arg_expr2 ...))
| (CAST_EXPR operand_expr)
binary_opcode :=
PLUS_EXPR
| MINUS_EXPR
| MUL_EXPR
| DIV_EXPR
| MOD_EXPR
| LSHIFT_EXPR
| RSHIFT_EXPR
| BIT_AND_EXPR
| BIT_OR_EXPR
| BIT_XOR_EXPR
asg_binary_opcode :=
ASG_PLUS_EXPR
| ASG_MINUS_EXPR
| ASG_MUL_EXPR
| ASG_DIV_EXPR
| ASG_MOD_EXPR
| ASG_BIT_AND_EXPR
| ASG_LSHIFT_EXPR
| ASG_RSHIFT_EXPR
| ASG_BIT_OR_EXPR
| ASG_BIT_XOR_EXPR
unary_opcode :=
UNARY_MINUS_EXPR
| BIT_NOT_EXPR
logical_binary_opcode :=
LOG_EQ_EXPR
| LOG_NEQ_EXPR
| LOG_GE_EXPR
| LOG_GT_EXPR
| LOG_LE_EXPR
| LOG_LT_EXPR
| LOG_AND_EXPR
| LOG_OR_EXPR
logical_unary_opcode :=
LOG_NOT_EXPR
- ASSIGN_EXPR またはassign_binary_opcodeのleft_exprは、lvalueでなく
てはならない。
- POST_INCR_EXPR, POST_DECR_EXPRのoperand_exprはlvalueでなくてはな
らない。
- CAST_EXPRは、この式の持つタイプに型変換(cast)する。
Xcode primary expression
primary_expr :=
constant_expr
| (POINTER_REF addr_expr)
| var_ref_expr
| member_ref_expr
| array_ref_expr
定数は、以下のように表現する。
constant_expr :=
(INT_CONSTANT number)
| (FLOAT_CONSTANT num1 num2)
| (LONGLONG_CONSTANT num1 num2)
| (STRING_CONSTANT "...")
| (MOE_CONSTANT moe_name)
| (FUNC_ADDR func_name)
- 定数のデータ型は、Xcodeのデータ型で指定する。
- MOE_CONSTANTの場合は、この式を含むスコープのシンボルテーブルのな
かにmo_nameがふくまれていなくてはならない。
- LONGLONG_CONSTANTは、64ビット定数を指定する。上位と下位にわけて格
納する。
- FLOAT_CONATANTは、32ビットであっても、doubleに変換して格納してい
る。
- FUNC_ADDRは関数のアドレスを表現する。
変数への参照は、大域変数、パラメータ変数、局所変数、それぞれに対して、
異なるXcodeを用いる。変数のアドレスを参照するVAR_ADDR, PARAM_ADDR,
LVAR_ADDRと、変数を参照するVAR,PARAM,LVARがある。
var_ref_expr :=
(VAR var_name)
| (VAR_ADDR var_name)
| (PRAAM var_name)
| (PARAM_ADDR var_name)
| (LVAR var_name)
| (LVAR_ADDR var_name)
- (VAR var_name) は、(POINTER_REF (VAR_ADDR var_name))と等価。
- (PARAM var_name) は、(POINTER_REF (PARAM_ADDR var_name))と等価。
- (LVAR var_name) は、(POINTER_REF (LVAR_ADDR var_name))と等価。
- var_nameは、それぞれの対応するスコープに定義されていなくてはなら
ない。
- (LVAR_ADDR var_name)は,Cでの表現は&var_name
配列要素への参照は、配列変数のアドレスを用いてアドレス計算し、
POINTER_REFで要素にアクセスする。(検討事項)
array_ref_expr :=
(ARRAY_ADDR var_name)
| (LARRAY_ADDR var_name)
構造体メンバへの参照は、参照アドレスを参照するMEMBER_ADDRとメンバを参
照するMEMBER_REF、メンバ配列のアドレスを参照するMEMBER_ARRAY_ADDRがあ
る。
member_ref_expr :=
(MEMBER_REF addr_expr (IDENT member_name))
| (MEMBER_ADDR addr_expr (IDENT member_name))
| (MEMBER_ARRAY_ADDR addr_expr (IDENT member_name))
- (MEMBER_REF addr (IDNET member_name)) は
(POINTER_REF (MEMBER_ADDR add (IDENT member_name))) と等価。
例1:
int a[10];
int xyz;
struct { int x; int y;} S;
foo() {
int *p;
p = &xyz; /* 文1 */
a[4] = S.y; /* 文2 */
}
文1:
(EXPR_STATEMENT
(ASSIGN_EXPR:P6fc98
(POINTER_REF:P6fc98
(LVAR_ADDR:P70768 p))
(VAR_ADDR:P70828 xyz)))
もしくは、
(EXPR_STATEMENT
(ASSIGN_EXPR:P6fc98
(LVAR:P6fc98 p)
(VAR_ADDR:P70828 xyz)))
文2:
(EXPR_STATEMENT
(ASSIGN_EXPR:int
(POINTER_REF:int
(PLUS_EXPR:P708e8
(ARRAY_ADDR:P708e8 a)
(INT_CONSTANT:int 4)))
(POINTER_REF:int
(MEMBER_ADDR:int
(VAR_ADDR:P70988 S)
(IDENT:int y)))))
もしくは: (検討事項)
(EXPR_STATEMENT
(ASSIGN_EXPR:int
(ARRAY_REF:int
(ARRAY_ADDR:P708e8 a)
(INT_CONSTANT:int 4))
(MEMBER_REF:int
(VAR_ADDR:P70988 S)
(IDENT:int y))))