summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog19
-rw-r--r--src/arch/x86/op_call.c4
-rw-r--r--src/format/elf/e_elf.c18
-rw-r--r--src/format/elf/elf-int.h10
-rw-r--r--src/format/elf/section.c186
-rw-r--r--src/format/elf/section.h36
-rw-r--r--src/format/elf/strings.c33
-rw-r--r--src/format/elf/symbol.c112
8 files changed, 324 insertions, 94 deletions
diff --git a/ChangeLog b/ChangeLog
index e4d24d6..b9dbaf5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2008-10-29 Cyrille Bagard <nocbos@gmail.com>
+
+ * src/arch/x86/op_call.c:
+ Save the type (AIT_CALL) of all kinds of 'call' instruction.
+
+ * src/format/elf/e_elf.c:
+ Update calls to the functions handling the sections.
+
+ * src/format/elf/elf-int.h:
+ Move the ELF section header wrapper to section.h.
+
+ * src/format/elf/section.c:
+ * src/format/elf/section.h:
+ Rewrite the way to look for given sections.
+
+ * src/format/elf/strings.c:
+ * src/format/elf/symbol.c:
+ Do not rely on section names anymore.
+
2008-10-27 Cyrille Bagard <nocbos@gmail.com>
* src/arch/x86/instruction.h:
diff --git a/src/arch/x86/op_call.c b/src/arch/x86/op_call.c
index 980a5e7..7641214 100644
--- a/src/arch/x86/op_call.c
+++ b/src/arch/x86/op_call.c
@@ -57,6 +57,8 @@ asm_x86_instr *x86_read_instr_call_rel1632(const uint8_t *data, off_t *pos, off_
ASM_INSTRUCTION(result)->opcode = data[(*pos)++];
+ ASM_INSTRUCTION(result)->type = AIT_CALL;
+
if (!x86_read_one_operand(result, data, pos, len, X86_OTP_REL1632, oprsize, offset))
{
free(result);
@@ -95,6 +97,8 @@ asm_x86_instr *x86_read_instr_call_rm1632(const uint8_t *data, off_t *pos, off_t
ASM_INSTRUCTION(result)->opcode = data[(*pos)++];
+ ASM_INSTRUCTION(result)->type = AIT_CALL;
+
if (!x86_read_one_operand(result, data, pos, len, X86_OTP_RM1632, oprsize))
{
free(result);
diff --git a/src/format/elf/e_elf.c b/src/format/elf/e_elf.c
index c2e49b1..a9eacea 100644
--- a/src/format/elf/e_elf.c
+++ b/src/format/elf/e_elf.c
@@ -71,7 +71,7 @@ elf_format *load_elf(const uint8_t *content, off_t length)
EXE_FORMAT(result)->length = length;
EXE_FORMAT(result)->get_def_parts = (get_def_parts_fc)get_elf_default_code_parts;
- EXE_FORMAT(result)->find_section = (find_section_fc)find_elf_section;
+ EXE_FORMAT(result)->find_section = (find_section_fc)find_elf_section_content_by_name;
EXE_FORMAT(result)->get_symbols = (get_symbols_fc)get_elf_symbols;
EXE_FORMAT(result)->resolve_symbol = (resolve_symbol_fc)resolve_elf_symbol;
@@ -142,7 +142,7 @@ bin_part **get_elf_default_code_parts(const elf_format *format, size_t *count)
if (format->sec_size > 0)
{
- if (find_elf_section(format, ".plt", &offset, &size, &voffset))
+ if (find_elf_section_content_by_name(format, ".plt", &offset, &size, &voffset))
{
part = create_bin_part();
@@ -154,7 +154,7 @@ bin_part **get_elf_default_code_parts(const elf_format *format, size_t *count)
}
- if (find_elf_section(format, ".init", &offset, &size, &voffset))
+ if (find_elf_section_content_by_name(format, ".init", &offset, &size, &voffset))
{
part = create_bin_part();
@@ -166,7 +166,7 @@ bin_part **get_elf_default_code_parts(const elf_format *format, size_t *count)
}
- if (find_elf_section(format, ".text", &offset, &size, &voffset))
+ if (find_elf_section_content_by_name(format, ".text", &offset, &size, &voffset))
{
part = create_bin_part();
@@ -178,7 +178,7 @@ bin_part **get_elf_default_code_parts(const elf_format *format, size_t *count)
}
- if (find_elf_section(format, ".fini", &offset, &size, &voffset))
+ if (find_elf_section_content_by_name(format, ".fini", &offset, &size, &voffset))
{
part = create_bin_part();
@@ -202,15 +202,15 @@ bin_part **get_elf_default_code_parts(const elf_format *format, size_t *count)
memcpy(&shdr, &EXE_FORMAT(format)->content[offset], format->header.e_shentsize);
- if (ELF_SHDR(format, shdr, sh_flags) & SHF_EXECINSTR)
+ if (ELF_SHDR(format, &shdr, sh_flags) & SHF_EXECINSTR)
{
part = create_bin_part();
/* TODO : nom */
- set_bin_part_values(part, ELF_SHDR(format, shdr, sh_offset),
- ELF_SHDR(format, shdr, sh_size),
- ELF_SHDR(format, shdr, sh_addr));
+ set_bin_part_values(part, ELF_SHDR(format, &shdr, sh_offset),
+ ELF_SHDR(format, &shdr, sh_size),
+ ELF_SHDR(format, &shdr, sh_addr));
result = (bin_part **)realloc(result, ++(*count) * sizeof(bin_part *));
result[*count - 1] = part;
diff --git a/src/format/elf/elf-int.h b/src/format/elf/elf-int.h
index 02cc2dd..0931654 100644
--- a/src/format/elf/elf-int.h
+++ b/src/format/elf/elf-int.h
@@ -74,16 +74,6 @@ struct _elf_format
-/* En-tête de section ELF */
-typedef union _Elf_Shdr
-{
- Elf32_Shdr section32; /* Version 32 bits */
- Elf64_Shdr section64; /* Version 64 bits */
-
-} Elf_Shdr;
-
-#define ELF_SHDR(fmt, sec, fld) (fmt->is_32b ? sec.section32.fld : sec.section64.fld)
-
/* En-tête de programme ELF */
typedef union _Elf_Phdr
diff --git a/src/format/elf/section.c b/src/format/elf/section.c
index f16e002..7ad8363 100644
--- a/src/format/elf/section.c
+++ b/src/format/elf/section.c
@@ -32,13 +32,6 @@
-/* Teste si une section correspond à celle recherchée. */
-bool find_target_elf_section(const elf_format *, const char *, Elf32_Off, Elf32_Shdr *);
-
-
-
-
-
/******************************************************************************
* *
* Paramètres : format = description de l'exécutable à compléter. *
@@ -75,12 +68,11 @@ bool read_elf_section_names(elf_format *format)
/******************************************************************************
* *
-* Paramètres : format = description de l'exécutable à consulter. *
-* target = nom de la section recherchée. *
-* offset = position de la section à tester. *
-* data = description de la section trouvée. [OUT] *
+* Paramètres : format = description de l'exécutable à consulter. *
+* name = nom de la section recherchée. *
+* section = ensemble d'informations à faire remonter. [OUT] *
* *
-* Description : Teste si une section correspond à celle recherchée. *
+* Description : Recherche une section donnée au sein de binaire par nom. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -88,20 +80,23 @@ bool read_elf_section_names(elf_format *format)
* *
******************************************************************************/
-bool find_target_elf_section(const elf_format *format, const char *target, Elf32_Off offset, Elf32_Shdr *data)
+bool find_elf_section_by_name(const elf_format *format, const char *name, Elf_Shdr *section)
{
- bool result; /* Conclusion à retourner */
- Elf32_Shdr section; /* Section à analyser */
+ bool result; /* Bilan à retourner */
+ uint16_t i; /* Boucle de parcours */
- result = false;
+ /* Si on perd notre temps... */
+ if (format->sec_size == 0) return false;
- if ((offset + sizeof(Elf32_Shdr)) >= EXE_FORMAT(format)->length) return false;
+ result = false;
- memcpy(&section, &EXE_FORMAT(format)->content[offset], sizeof(Elf32_Shdr));
+ for (i = 0; i < format->header.e_shnum && !result; i++)
+ {
+ find_elf_section_by_index(format, i, section);
- result = (strcmp(target, &format->sec_names[section.sh_name]) == 0);
+ result = (strcmp(name, &format->sec_names[ELF_SHDR(format, section, sh_name)]) == 0);
- if (result) *data = section;
+ }
return result;
@@ -110,13 +105,109 @@ bool find_target_elf_section(const elf_format *format, const char *target, Elf32
/******************************************************************************
* *
+* Paramètres : format = description de l'exécutable à consulter. *
+* type = type de la section recherchée. *
+* sections = tableau d'informations à faire remonter. [OUT] *
+* count = nombre d'éléments présents dans le tableau. [OUT] *
+* *
+* Description : Recherche une section donnée au sein de binaire par type. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool find_elf_section_by_type(const elf_format *format, uint16_t type, Elf_Shdr **sections, size_t *count)
+{
+ uint16_t i; /* Boucle de parcours */
+ Elf_Shdr section; /* Section à analyser */
+
+ *sections = NULL;
+ *count = 0;
+
+ for (i = 0; i < format->header.e_shnum; i++)
+ {
+ find_elf_section_by_index(format, i, &section);
+
+ if (type == ELF_SHDR(format, &section, sh_type))
+ {
+ *sections = (Elf_Shdr *)realloc(*sections, ++(*count) * sizeof(Elf_Shdr));
+ (*sections)[*count - 1] = section;
+ }
+
+ }
+
+ return (*count > 0);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : format = description de l'exécutable à consulter. *
+* index = indice de la section recherchée. *
+* section = ensemble d'informations à faire remonter. [OUT] *
+* *
+* Description : Recherche une section donnée au sein de binaire par indice. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool find_elf_section_by_index(const elf_format *format, uint16_t index, Elf_Shdr *section)
+{
+ off_t offset; /* Emplacement à venir lire */
+
+ if (index >= format->header.e_shnum) return false;
+
+ offset = format->header.e_shoff + format->header.e_shentsize * index;
+
+ memcpy(section, &EXE_FORMAT(format)->content[offset], ELF_SIZEOF_SHDR(format));
+
+ return true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : format = description de l'exécutable à consulter. *
+* section = section à consulter. *
+* offset = position de la section trouvée. [OUT] *
+* size = taille de la section trouvée. [OUT] *
+* voffset = adresse virtuelle de la section trouvée. [OUT] *
+* *
+* Description : Fournit les adresses et taille contenues dans une section. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void get_elf_section_content(const elf_format *format, const Elf_Shdr *section, off_t *offset, off_t *size, uint64_t *voffset)
+{
+ *offset = ELF_SHDR(format, section, sh_offset);
+ *size = ELF_SHDR(format, section, sh_size);
+
+ if (voffset != NULL)
+ *voffset = ELF_SHDR(format, section, sh_addr);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : format = description de l'exécutable à consulter. *
-* target = nom de la section recherchée. *
+* name = nom de la section recherchée. *
* offset = position de la section trouvée. [OUT] *
* size = taille de la section trouvée. [OUT] *
* voffset = adresse virtuelle de la section trouvée. [OUT] *
* *
-* Description : Recherche une section donnée au sein de binaire. *
+* Description : Recherche une zone donnée au sein de binaire par nom. *
* *
* Retour : Bilan de l'opération. *
* *
@@ -124,35 +215,46 @@ bool find_target_elf_section(const elf_format *format, const char *target, Elf32
* *
******************************************************************************/
-bool find_elf_section(const elf_format *format, const char *target, off_t *offset, off_t *size, uint64_t *voffset)
+bool find_elf_section_content_by_name(const elf_format *format, const char *name, off_t *offset, off_t *size, uint64_t *voffset)
{
- bool result;
- Elf32_Half i;
- Elf32_Shdr data;
+ bool result; /* Bilan à retourner */
+ Elf_Shdr section; /* Section trouvée ou non */
- /* Si on perd notre temps... */
- if (format->sec_size == 0) return false;
+ result = find_elf_section_by_name(format, name, &section);
- result = false;
+ if (result)
+ get_elf_section_content(format, &section, offset, size, voffset);
- for (i = 0; i < format->header.e_shnum; i++)
- {
- if (i == format->header.e_shstrndx) continue;
+ return result;
+
+}
- if (find_target_elf_section(format, target,
- format->header.e_shoff + format->header.e_shentsize * i, &data))
- {
- *offset = data.sh_offset;
- *size = data.sh_size;
- if (voffset != NULL)
- *voffset = data.sh_addr;
+/******************************************************************************
+* *
+* Paramètres : format = description de l'exécutable à consulter. *
+* index = indice de la section recherchée. *
+* offset = position de la section trouvée. [OUT] *
+* size = taille de la section trouvée. [OUT] *
+* voffset = adresse virtuelle de la section trouvée. [OUT] *
+* *
+* Description : Recherche une zone donnée au sein de binaire par indice. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- result = true;
+bool find_elf_section_content_by_index(const elf_format *format, uint16_t index, off_t *offset, off_t *size, uint64_t *voffset)
+{
+ bool result; /* Bilan à retourner */
+ Elf_Shdr section; /* Section trouvée ou non */
- }
+ result = find_elf_section_by_index(format, index, &section);
- }
+ if (result)
+ get_elf_section_content(format, &section, offset, size, voffset);
return result;
diff --git a/src/format/elf/section.h b/src/format/elf/section.h
index b84fe76..6bc3a75 100644
--- a/src/format/elf/section.h
+++ b/src/format/elf/section.h
@@ -25,15 +25,47 @@
#define _FORMAT_ELF_SECTION_H
+#include <elf.h>
+
+
#include "e_elf.h"
+/* En-tête de section ELF */
+typedef union _Elf_Shdr
+{
+ Elf32_Shdr section32; /* Version 32 bits */
+ Elf64_Shdr section64; /* Version 64 bits */
+
+} Elf_Shdr;
+
+
+#define ELF_SIZEOF_SHDR(fmt) (fmt->is_32b ? sizeof(Elf32_Shdr) : sizeof(Elf64_Shdr))
+
+#define ELF_SHDR(fmt, shdr, fld) (fmt->is_32b ? (shdr)->section32.fld : (shdr)->section64.fld)
+
+
/* Charge en mémoire la liste humaine des sections. */
bool read_elf_section_names(elf_format *);
-/* Recherche une section donnée au sein de binaire. */
-bool find_elf_section(const elf_format *, const char *, off_t *, off_t *, uint64_t *);
+/* Recherche une section donnée au sein de binaire par nom. */
+bool find_elf_section_by_name(const elf_format *, const char *, Elf_Shdr *);
+
+/* Recherche une section donnée au sein de binaire par type. */
+bool find_elf_section_by_type(const elf_format *, uint16_t, Elf_Shdr **, size_t *);
+
+/* Recherche une section donnée au sein de binaire par indice. */
+bool find_elf_section_by_index(const elf_format *, uint16_t, Elf_Shdr *);
+
+/* Fournit les adresses et taille contenues dans une section. */
+void get_elf_section_content(const elf_format *, const Elf_Shdr *, off_t *, off_t *, uint64_t *);
+
+/* Recherche une zone donnée au sein de binaire par nom. */
+bool find_elf_section_content_by_name(const elf_format *, const char *, off_t *, off_t *, uint64_t *);
+
+/* Recherche une zone donnée au sein de binaire par indice. */
+bool find_elf_section_content_by_index(const elf_format *, uint16_t, off_t *, off_t *, uint64_t *);
diff --git a/src/format/elf/strings.c b/src/format/elf/strings.c
index 3d373a6..049f6d4 100644
--- a/src/format/elf/strings.c
+++ b/src/format/elf/strings.c
@@ -56,9 +56,38 @@ bool find_all_elf_strings(elf_format *format)
off_t str_start; /* Début de section */
off_t str_size; /* Taille de section */
uint64_t str_vaddr; /* Adresse virtuelle associée */
+ Elf_Shdr *sections; /* Groupe de sections trouvées */
+ size_t count; /* Quantité de données */
+ size_t i; /* Boucle de parcours */
+
+ /* Données en lecture seule */
+
+ if (find_elf_section_content_by_name(format, ".rodata", &str_start, &str_size, &str_vaddr))
+ parse_elf_string_data(format, str_start, str_size, str_vaddr);
+
+ else
+ {
+ find_elf_section_by_type(format, SHT_PROGBITS, &sections, &count);
- if (find_elf_section(format, ".rodata", &str_start, &str_size, &str_vaddr))
+ for (i = 0; i < count; i++)
+ if (ELF_SHDR(format, &sections[i], sh_flags) == SHF_ALLOC
+ || (ELF_SHDR(format, &sections[i], sh_flags) & SHF_STRINGS))
+ {
+ get_elf_section_content(format, &sections[i], &str_start, &str_size, &str_vaddr);
+ parse_elf_string_data(format, str_start, str_size, str_vaddr);
+ }
+
+ }
+
+ /* Chaîne de caractères déclarées */
+
+ find_elf_section_by_type(format, SHT_STRTAB, &sections, &count);
+
+ for (i = 0; i < count; i++)
+ {
+ get_elf_section_content(format, &sections[i], &str_start, &str_size, &str_vaddr);
parse_elf_string_data(format, str_start, str_size, str_vaddr);
+ }
return true;
@@ -85,6 +114,8 @@ bool parse_elf_string_data(elf_format *format, const off_t start, const off_t si
off_t i; /* Boucle de parcours */
off_t end; /* Position de fin de chaîne */
+ if (vaddress == 0) return false;
+
for (i = start; i < (start + size); i++)
if (isprint(EXE_FORMAT(format)->content[i]))
{
diff --git a/src/format/elf/symbol.c b/src/format/elf/symbol.c
index 8fa5690..4b7740d 100644
--- a/src/format/elf/symbol.c
+++ b/src/format/elf/symbol.c
@@ -84,74 +84,105 @@ bool load_elf_symbol_table_64(elf_format *, const off_t *, const off_t *, const
bool load_elf_symbols(elf_format *format)
{
bool result; /* Bilan à retourner */
-
-
+ Elf_Shdr *sections; /* Groupe de sections trouvées */
+ size_t count; /* Quantité de données */
+ size_t i; /* Boucle de parcours */
+ Elf_Shdr section; /* Section trouvée ou non */
off_t sym_start; /* Début de section */
off_t sym_size; /* Taille de section */
off_t str_start; /* Début de section */
off_t str_size; /* Taille de section */
-
-
- off_t plt_start; /* Début de section */
- off_t plt_size; /* Taille de section */
+ off_t rel_start; /* Début de section */
+ off_t rel_size; /* Taille de section */
off_t dyn_start; /* Début de section */
off_t dyn_size; /* Taille de section */
asm_instr **instructions; /* Instructions décodées */
- size_t count; /* Quantité d'instructions */
- result = find_elf_section(format, ".symtab", &sym_start, &sym_size, NULL);
+ result = true;
- result &= find_elf_section(format, ".strtab", &str_start, &str_size, NULL);
+ /* Table des symboles */
- if (result)
+ find_elf_section_by_type(format, SHT_SYMTAB, &sections, &count);
+
+ for (i = 0; i < count; i++)
{
+ /* Section ".symtab" */
+ get_elf_section_content(format, &sections[i], &sym_start, &sym_size, NULL);
+ /* Section ".strtab" */
- result = load_elf_symbol_table_32(format, &sym_start, &sym_size, &str_start, &str_size);
+ result &= find_elf_section_by_index(format, ELF_SHDR(format, &sections[i], sh_link), &section);
+ get_elf_section_content(format, &section, &str_start, &str_size, NULL);
+ if (result)
+ {
- }
+ result = load_elf_symbol_table_32(format, &sym_start, &sym_size, &str_start, &str_size);
+ }
+ }
- result = find_elf_section(format, ".rel.plt", &plt_start, &plt_size, NULL);
+ /* Relocalisations dynamiques */
- result &= find_elf_section(format, ".dynsym", &dyn_start, &dyn_size, NULL);
+ find_elf_section_by_type(format, SHT_REL, &sections, &count);
- result &= find_elf_section(format, ".dynstr", &str_start, &str_size, NULL);
+ for (i = 0; i < count; i++)
+ {
+ /* Section ".rel.xxx" */
+ get_elf_section_content(format, &sections[i], &rel_start, &rel_size, NULL);
+ /* Section ".dynsym" */
- if (result)
- {
+ result &= find_elf_section_by_index(format, ELF_SHDR(format, &sections[i], sh_link), &section);
+
+ get_elf_section_content(format, &section, &dyn_start, &dyn_size, NULL);
+ /* Section ".dynstr" */
+ result &= find_elf_section_by_index(format, ELF_SHDR(format, &section, sh_link), &section);
- result = load_elf_relocation_table(format, &plt_start, &plt_size, &dyn_start, &dyn_size, &str_start, &str_size);
+ get_elf_section_content(format, &section, &str_start, &str_size, NULL);
+ /* Récupération (première partie) */
if (result)
{
- instructions = decode_elf_relocations(format, &count);
- translate_elf_relocations(format, instructions, count);
+ result = load_elf_relocation_table(format, &rel_start, &rel_size, &dyn_start, &dyn_size, &str_start, &str_size);
- /* TODO : free instructions */
+
}
+ }
+
+ free(sections);
+
+ /* Récupération (seconde partie) */
+
+ if (result)
+ {
+ instructions = decode_elf_relocations(format, &count);
+
+ translate_elf_relocations(format, instructions, count);
+
+ /* TODO : free instructions */
}
+
+
return result;
}
@@ -446,6 +477,9 @@ asm_instr **decode_elf_relocations(elf_format *format, size_t *count)
off_t rel_start; /* Début de section */
off_t rel_size; /* Taille de section */
uint64_t rel_vaddress; /* Adresse virtuelle associée */
+ Elf_Shdr *sections; /* Groupe de sections trouvées */
+ size_t sec_count; /* Quantité de données */
+ size_t i; /* Boucle de parcours */
off_t pos; /* Tête de lecture */
uint64_t offset; /* Adresse virtuelle courante */
asm_instr *instr; /* Instruction décodée */
@@ -456,17 +490,35 @@ asm_instr **decode_elf_relocations(elf_format *format, size_t *count)
result = NULL;
*count = 0;
- if (find_elf_section(format, ".plt", &rel_start, &rel_size, &rel_vaddress))
- for (pos = 0; pos < rel_size; )
- {
- offset = rel_vaddress + pos;
+ if (!find_elf_section_content_by_name(format, ".plt", &rel_start, &rel_size, &rel_vaddress))
+ {
+ printf("No .plt section found ! Trying to guess it...\n");
- instr = decode_instruction(proc, &EXE_FORMAT(format)->content[rel_start], &pos, rel_size, offset);
+ find_elf_section_by_type(format, SHT_PROGBITS, &sections, &sec_count);
- result = (asm_instr **)realloc(result, ++(*count) * sizeof(asm_instr *));
- result[*count - 1] = instr;
+ for (i = 0; i < sec_count; i++)
+ if (ELF_SHDR(format, &sections[i], sh_entsize) > 0)
+ {
+ get_elf_section_content(format, &sections[i], &rel_start, &rel_size, &rel_vaddress);
+ break;
+ }
- }
+ free(sections);
+
+ if (i == sec_count) return NULL;
+
+ }
+
+ for (pos = 0; pos < rel_size; )
+ {
+ offset = rel_vaddress + pos;
+
+ instr = decode_instruction(proc, &EXE_FORMAT(format)->content[rel_start], &pos, rel_size, offset);
+
+ result = (asm_instr **)realloc(result, ++(*count) * sizeof(asm_instr *));
+ result[*count - 1] = instr;
+
+ }
return result;
@@ -497,7 +549,7 @@ void translate_elf_relocations(elf_format *format, asm_instr **instructions, siz
for (i = 0; (i + 2) < count; )
{
- if (instructions[i]->type == AIT_JUMP
+ if ((instructions[i]->type == AIT_JUMP || instructions[i]->type == AIT_CALL)
&& instructions[i + 1]->type == AIT_PUSH
&& instructions[i + 2]->type == AIT_JUMP)
{