LCOV - code coverage report
Current view: top level - vm/jit/x86_64 - patcher.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 161 168 95.8 %
Date: 2017-07-14 10:03:36 Functions: 16 16 100.0 %

          Line data    Source code
       1             : /* src/vm/jit/x86_64/patcher.cpp - x86_64 code patching functions
       2             : 
       3             :    Copyright (C) 1996-2013
       4             :    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
       5             : 
       6             :    This file is part of CACAO.
       7             : 
       8             :    This program is free software; you can redistribute it and/or
       9             :    modify it under the terms of the GNU General Public License as
      10             :    published by the Free Software Foundation; either version 2, or (at
      11             :    your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful, but
      14             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :    General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program; if not, write to the Free Software
      20             :    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
      21             :    02110-1301, USA.
      22             : 
      23             : */
      24             : 
      25             : 
      26             : #include "config.h"
      27             : 
      28             : #include <stdint.h>
      29             : 
      30             : #include "vm/types.hpp"
      31             : 
      32             : #include "vm/jit/x86_64/codegen.hpp"
      33             : #include "vm/jit/x86_64/md.hpp"
      34             : 
      35             : #include "mm/memory.hpp"
      36             : 
      37             : #include "native/native.hpp"
      38             : 
      39             : #include "vm/jit/builtin.hpp"
      40             : #include "vm/class.hpp"
      41             : #include "vm/field.hpp"
      42             : #include "vm/initialize.hpp"
      43             : #include "vm/options.hpp"
      44             : #include "vm/resolve.hpp"
      45             : 
      46             : #include "vm/jit/patcher-common.hpp"
      47             : 
      48             : 
      49             : /* patcher_patch_code **********************************************************
      50             : 
      51             :    Just patches back the original machine code.
      52             : 
      53             : *******************************************************************************/
      54             : 
      55       71129 : void patcher_patch_code(patchref_t *pr)
      56             : {
      57       71129 :         *((uint16_t*) pr->mpc) = (uint16_t) pr->mcode;
      58       71129 :         md_icacheflush((void*) pr->mpc, PATCHER_CALL_SIZE);
      59       71129 : }
      60             : 
      61       12390 : static int32_t *patch_checked_location(int32_t *p, int32_t val)
      62             : {
      63       12390 :         assert(*p == 0);
      64             :         // verify that it's aligned
      65       12390 :         assert((((uintptr_t) p) & (4-1)) == 0);
      66       12390 :         *p = val;
      67       12390 :         return p;
      68             : }
      69             : 
      70         667 : static void checked_icache_flush(void *addr, int nbytes, int32_t *check_loc)
      71             : {
      72         667 :         assert((int8_t*) addr + nbytes - sizeof(int32_t) >= (int8_t*) check_loc);
      73         667 :         md_icacheflush(addr, nbytes);
      74         667 : }
      75             : 
      76             : /**
      77             :  * Check if the trap instruction at the given PC is valid.
      78             :  *
      79             :  * @param pc Program counter.
      80             :  *
      81             :  * @return true if valid, false otherwise.
      82             :  */
      83       71147 : bool patcher_is_valid_trap_instruction_at(void* pc)
      84             : {
      85       71147 :         uint16_t mcode = *((uint16_t*) pc);
      86             : 
      87             :         // Check for the undefined instruction we use.
      88       71147 :         return (mcode == 0x0b0f);
      89             : }
      90             : 
      91             : /**
      92             :  * Overwrites the MFENCE instruction at the indicated address with a 3-byte
      93             :  * NOP. The MFENCE instruction is not allowed to cross a (4-byte) word
      94             :  * boundary.
      95             :  *
      96             :  * @param pc Program counter.
      97             :  */
      98        1637 : static void patch_out_mfence(void *pc)
      99             : {
     100        1637 :         uint32_t *p = (uint32_t*) (((uintptr_t) pc) & ~3);
     101             : 
     102        1637 :         assert((((uintptr_t) pc) & 3) < 2);
     103        1637 :         if (((uintptr_t) pc) & 1)
     104           4 :                 *p = (*p & 0x000000ff) | 0x001f0f00;
     105             :         else
     106        1633 :                 *p = (*p & 0xff000000) | 0x00001f0f;
     107             : 
     108        1637 :         md_icacheflush(p, 4);
     109        1637 : }
     110             : 
     111             : /* patcher_resolve_classref_to_classinfo ***************************************
     112             : 
     113             :    ACONST:
     114             : 
     115             :    <patched call position>
     116             :    48 bf a0 f0 92 00 00 00 00 00    mov    $0x92f0a0,%rdi
     117             : 
     118             :    MULTIANEWARRAY:
     119             : 
     120             :    <patched call position>
     121             :    48 be 30 40 b2 00 00 00 00 00    mov    $0xb24030,%rsi
     122             :    48 89 e2                         mov    %rsp,%rdx
     123             :    48 b8 7c 96 4b 00 00 00 00 00    mov    $0x4b967c,%rax
     124             :    48 ff d0                         callq  *%rax
     125             : 
     126             :    ARRAYCHECKCAST:
     127             : 
     128             :    <patched call position>
     129             :    48 be b8 3f b2 00 00 00 00 00    mov    $0xb23fb8,%rsi
     130             :    48 b8 00 00 00 00 00 00 00 00    mov    $0x0,%rax
     131             :    48 ff d0                         callq  *%rax
     132             : 
     133             : *******************************************************************************/
     134             : 
     135       14079 : bool patcher_resolve_classref_to_classinfo(patchref_t *pr)
     136             : {
     137       14079 :         constant_classref* cr    = (constant_classref*) pr->ref;
     138       14079 :         uintptr_t*         datap = (uintptr_t*)         pr->datap;
     139             : 
     140             :         // Resolve the class.
     141       14079 :         classinfo* c = resolve_classref_eager(cr);
     142             : 
     143       14079 :         if (c == NULL)
     144           1 :                 return false;
     145             : 
     146             :         // Patch the class.
     147       14078 :         *datap = (uintptr_t) c;
     148             : 
     149             :         // Synchronize data cache.
     150       14078 :         md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P);
     151             : 
     152             :         // Patch back the original code.
     153       14078 :         patcher_patch_code(pr);
     154             : 
     155       14078 :         return true;
     156             : }
     157             : 
     158             : 
     159             : /* patcher_resolve_classref_to_vftbl *******************************************
     160             : 
     161             :    CHECKCAST (class):
     162             :    INSTANCEOF (class):
     163             : 
     164             :    <patched call position>
     165             : 
     166             : *******************************************************************************/
     167             : 
     168         556 : bool patcher_resolve_classref_to_vftbl(patchref_t *pr)
     169             : {
     170         556 :         constant_classref* cr    = (constant_classref*) pr->ref;
     171         556 :         uintptr_t*         datap = (uintptr_t*)         pr->datap;
     172             : 
     173             :         // Resolve the field.
     174         556 :         classinfo* c = resolve_classref_eager(cr);
     175             : 
     176         556 :         if (c == NULL)
     177           0 :                 return false;
     178             : 
     179             :         // Patch super class' vftbl.
     180         556 :         *datap = (uintptr_t) c->vftbl;
     181             : 
     182             :         // Synchronize data cache.
     183         556 :         md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P);
     184             : 
     185             :         // Patch back the original code.
     186         556 :         patcher_patch_code(pr);
     187             : 
     188         556 :         return true;
     189             : }
     190             : 
     191             : 
     192             : /* patcher_resolve_classref_to_flags *******************************************
     193             : 
     194             :    CHECKCAST/INSTANCEOF:
     195             : 
     196             :    <patched call position>
     197             : 
     198             : *******************************************************************************/
     199             : 
     200         599 : bool patcher_resolve_classref_to_flags(patchref_t *pr)
     201             : {
     202         599 :         constant_classref* cr    = (constant_classref*) pr->ref;
     203             : /*      int32_t*           datap = (int32_t*)           pr->datap; */
     204         599 :         uint8_t*           ra    = (uint8_t*)           pr->mpc;
     205             : 
     206             :         // Resolve the field.
     207         599 :         classinfo* c = resolve_classref_eager(cr);
     208             : 
     209         599 :         if (c == NULL)
     210           0 :                 return false;
     211             : 
     212         599 :         ra += PATCHER_CALL_SIZE;
     213         599 :         ra += PATCH_ALIGNMENT((uintptr_t) ra, 2, sizeof(int32_t));
     214             : 
     215             :         // Patch class flags.
     216             : /*      *datap = c->flags; */
     217         599 :         patch_checked_location((int32_t*) (ra + 2), c->flags);
     218             : 
     219             :         // Synchronize data cache.
     220             : /*      md_dcacheflush(datap, sizeof(int32_t)); */
     221         599 :         md_icacheflush(ra + 2, sizeof(int32_t));
     222             : 
     223             :         // Patch back the original code.
     224         599 :         patcher_patch_code(pr);
     225             : 
     226         599 :         return true;
     227             : }
     228             : 
     229             : 
     230             : /* patcher_get_putstatic *******************************************************
     231             : 
     232             :    Machine code:
     233             : 
     234             :    <patched call position>
     235             :    4d 8b 15 86 fe ff ff             mov    -378(%rip),%r10
     236             :    49 8b 32                         mov    (%r10),%rsi
     237             : 
     238             : *******************************************************************************/
     239             : 
     240       18170 : bool patcher_get_putstatic(patchref_t *pr)
     241             : {
     242       18170 :         unresolved_field* uf    = (unresolved_field*) pr->ref;
     243       18170 :         uintptr_t*        datap = (uintptr_t*)        pr->datap;
     244       18170 :         uint8_t*          ra    = (uint8_t*)          pr->mpc;
     245             : 
     246             :         // Resolve the field.
     247       18170 :         fieldinfo* fi = resolve_field_eager(uf);
     248             : 
     249       18170 :         if (fi == NULL)
     250           0 :                 return false;
     251             : 
     252       18170 :         ra += PATCHER_CALL_SIZE;
     253             : 
     254             :         // Check if the field's class is initialized/
     255       18170 :         if (!(fi->clazz->state & CLASS_INITIALIZED))
     256        2703 :                 if (!initialize_class(fi->clazz))
     257           2 :                         return false;
     258             : 
     259             :         // Patch the field value's address.
     260       18168 :         *datap = (uintptr_t) fi->value;
     261             : 
     262       18168 :         if (pr->disp_mb && !(fi->flags & ACC_VOLATILE))
     263        1339 :                 patch_out_mfence(ra + pr->disp_mb - 2);
     264             : 
     265             :         // Synchronize data cache.
     266       18168 :         md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P);
     267             : 
     268             :         // Patch back the original code.
     269       18168 :         patcher_patch_code(pr);
     270             : 
     271       18168 :         return true;
     272             : }
     273             : 
     274             : 
     275             : /* patcher_get_putfield ********************************************************
     276             : 
     277             :    Machine code:
     278             : 
     279             :    <patched call position>
     280             :    45 8b 8f 00 00 00 00             mov    0x0(%r15),%r9d
     281             : 
     282             : *******************************************************************************/
     283             : 
     284         630 : bool patcher_get_putfield(patchref_t *pr)
     285             : {
     286         630 :         uint8_t*          pc = (uint8_t*)          pr->mpc;
     287         630 :         unresolved_field* uf = (unresolved_field*) pr->ref;
     288             : 
     289             :         // Resolve the field.
     290         630 :         fieldinfo* fi = resolve_field_eager(uf);
     291             : 
     292         630 :         if (fi == NULL)
     293           1 :                 return false;
     294             : 
     295         629 :         pc += PATCHER_CALL_SIZE;
     296             : 
     297         629 :         int disp = -sizeof(int32_t) + pr->patch_align;
     298         629 :         patch_checked_location((int32_t*) (pc + disp), fi->offset);
     299             : 
     300         629 :         if (pr->disp_mb && !(fi->flags & ACC_VOLATILE))
     301         277 :                 patch_out_mfence(pc + pr->disp_mb - 2);
     302             : 
     303             :         // Synchronize instruction cache.
     304         629 :         md_icacheflush(pc, disp + sizeof(int32_t));
     305             : 
     306             :         // Patch back the original code.
     307         629 :         patcher_patch_code(pr);
     308             : 
     309         629 :         return true;
     310             : }
     311             : 
     312             : 
     313             : /* patcher_putfieldconst *******************************************************
     314             : 
     315             :    Machine code:
     316             : 
     317             :    <patched call position>
     318             :    41 c7 85 00 00 00 00 7b 00 00 00    movl   $0x7b,0x0(%r13)
     319             : 
     320             : *******************************************************************************/
     321             : 
     322          22 : bool patcher_putfieldconst(patchref_t *pr)
     323             : {
     324          22 :         uint8_t*          pc = (uint8_t*)          pr->mpc;
     325          22 :         unresolved_field* uf = (unresolved_field*) pr->ref;
     326             : 
     327             :         // Resolve the field.
     328          22 :         fieldinfo* fi = resolve_field_eager(uf);
     329             : 
     330          22 :         if (fi == NULL)
     331           1 :                 return false;
     332             : 
     333          21 :         pc += PATCHER_CALL_SIZE;
     334             : 
     335          21 :         int disp = -2*sizeof(int32_t) + pr->patch_align;
     336          21 :         patch_checked_location((int32_t*) (pc + disp), fi->offset);
     337             : 
     338          21 :         if (pr->disp_mb && !(fi->flags & ACC_VOLATILE))
     339          21 :                 patch_out_mfence(pc + pr->disp_mb - 2);
     340             : 
     341             :         // Synchronize instruction cache.
     342          21 :         md_icacheflush(pc, disp + sizeof(int32_t));
     343             : 
     344             :         // Patch back the original code.
     345          21 :         patcher_patch_code(pr);
     346             : 
     347          21 :         return true;
     348             : }
     349             : 
     350             : 
     351             : /* patcher_invokestatic_special ************************************************
     352             : 
     353             :    Machine code:
     354             : 
     355             :    <patched call position>
     356             :    49 ba 00 00 00 00 00 00 00 00    mov    $0x0,%r10
     357             :    49 ff d2                         callq  *%r10
     358             : 
     359             : *******************************************************************************/
     360             : 
     361       22894 : bool patcher_invokestatic_special(patchref_t *pr)
     362             : {
     363       22894 :         unresolved_method* um    = (unresolved_method*) pr->ref;
     364       22894 :         uintptr_t*         datap = (uintptr_t*)         pr->datap;
     365             : 
     366             :         // Resolve the method.
     367       22894 :         methodinfo* m = resolve_method_eager(um);
     368             : 
     369       22894 :         if (m == NULL)
     370           0 :                 return false;
     371             : 
     372             :         // Patch stubroutine.
     373       22894 :         *datap = (uintptr_t) m->stubroutine;
     374             : 
     375             :         // Synchronize data cache.
     376       22894 :         md_dcacheflush((void*) pr->datap, SIZEOF_VOID_P);
     377             : 
     378             :         // Patch back the original code.
     379       22894 :         patcher_patch_code(pr);
     380             : 
     381       22894 :         return true;
     382             : }
     383             : 
     384             : 
     385             : /* patcher_invokevirtual *******************************************************
     386             : 
     387             :    Machine code:
     388             : 
     389             :    <patched call position>
     390             :    4c 8b 17                         mov    (%rdi),%r10
     391             :    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
     392             :    48 ff d0                         callq  *%rax
     393             : 
     394             : *******************************************************************************/
     395             : 
     396        9812 : bool patcher_invokevirtual(patchref_t *pr)
     397             : {
     398        9812 :         uint8_t*           pc = (uint8_t*)           pr->mpc;
     399        9812 :         unresolved_method* um = (unresolved_method*) pr->ref;
     400             : 
     401             :         // Resovlve the method.
     402        9812 :         methodinfo* m = resolve_method_eager(um);
     403             : 
     404        9812 :         if (m == NULL)
     405           5 :                 return false;
     406             : 
     407        9807 :         pc += PATCHER_CALL_SIZE;
     408        9807 :         pc += PATCH_ALIGNMENT((uintptr_t) pc, 6, sizeof(int32_t));
     409             : 
     410             :         // Patch vftbl index.
     411        9807 :         patch_checked_location((int32_t*) (pc + 6), (int32_t) (OFFSET(vftbl_t, table[0]) + sizeof(methodptr) * m->vftblindex));
     412             : 
     413             :         // Synchronize instruction cache.
     414        9807 :         md_icacheflush(pc + 3 + 3, SIZEOF_VOID_P);
     415             : 
     416             :         // Patch back the original code.
     417        9807 :         patcher_patch_code(pr);
     418             : 
     419        9807 :         return true;
     420             : }
     421             : 
     422             : 
     423             : /* patcher_invokeinterface *****************************************************
     424             : 
     425             :    Machine code:
     426             : 
     427             :    <patched call position>
     428             :    4c 8b 17                         mov    (%rdi),%r10
     429             :    4d 8b 92 00 00 00 00             mov    0x0(%r10),%r10
     430             :    49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
     431             :    48 ff d0                         callq  *%rax
     432             : 
     433             : *******************************************************************************/
     434             : 
     435         624 : bool patcher_invokeinterface(patchref_t *pr)
     436             : {
     437         624 :         uint8_t*           pc = (uint8_t*)           pr->mpc;
     438         624 :         unresolved_method* um = (unresolved_method*) pr->ref;
     439             : 
     440             :         // Resolve the method.
     441         624 :         methodinfo* m = resolve_method_eager(um);
     442             : 
     443         624 :         if (m == NULL)
     444           0 :                 return false;
     445             : 
     446         624 :         pc += PATCHER_CALL_SIZE;
     447         624 :         pc += PATCH_ALIGNMENT((uintptr_t) pc, 6, sizeof(int32_t));
     448             : 
     449             :         // Patch interfacetable index.
     450         624 :         patch_checked_location((int32_t*) (pc + 6), (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - sizeof(methodptr) * m->clazz->index));
     451             : 
     452         624 :         int disp = PATCH_ALIGNMENT((uintptr_t) (pc + 3 + 7), 3, sizeof(int32_t));
     453         624 :         pc += disp;
     454             :         // Patch method offset.
     455         624 :         int32_t *loc = patch_checked_location((int32_t*) (pc + 3 + 7 + 3), (int32_t) (sizeof(methodptr) * (m - m->clazz->methods)));
     456             : 
     457             :         // Synchronize instruction cache.
     458         624 :         checked_icache_flush(pc + 6, SIZEOF_VOID_P + 3 + SIZEOF_VOID_P + disp, loc);
     459             : 
     460             :         // Patch back the original code.
     461         624 :         patcher_patch_code(pr);
     462             : 
     463         624 :         return true;
     464             : }
     465             : 
     466             : 
     467             : /* patcher_checkcast_interface *************************************************
     468             : 
     469             :    Machine code:
     470             : 
     471             :    <patched call position>
     472             :    45 8b 9a 1c 00 00 00             mov    0x1c(%r10),%r11d
     473             :    41 81 fb 00 00 00 00             cmp    $0x0,%r11d
     474             :    0f 8f 08 00 00 00                jg     0x00002aaaaae511d5
     475             :    48 8b 0c 25 03 00 00 00          mov    0x3,%rcx
     476             :    4d 8b 9a 00 00 00 00             mov    0x0(%r10),%r11
     477             : 
     478             : *******************************************************************************/
     479             : 
     480          13 : bool patcher_checkcast_interface(patchref_t *pr)
     481             : {
     482          13 :         uint8_t*           pc = (uint8_t*)           pr->mpc;
     483          13 :         constant_classref* cr = (constant_classref*) pr->ref;
     484             : 
     485             :         // Resolve the class.
     486          13 :         classinfo* c = resolve_classref_eager(cr);
     487             : 
     488          13 :         if (c == NULL)
     489           0 :                 return false;
     490             : 
     491          13 :         pc += PATCHER_CALL_SIZE;
     492          13 :         pc += PATCH_ALIGNMENT((uintptr_t) pc, 10, sizeof(int32_t));
     493             : 
     494             :         // Patch super class index.
     495          13 :         patch_checked_location((int32_t*) (pc + 10), c->index);
     496             : 
     497          13 :         int disp = PATCH_ALIGNMENT((uintptr_t) (pc + 7 + 7 + 6 + 8), 3, sizeof(int32_t));
     498          13 :         pc += disp;
     499          13 :         int32_t *loc = patch_checked_location((int32_t*) (pc + 7 + 7 + 6 + 8 + 3), (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*)));
     500             : 
     501             :         // Synchronize instruction cache.
     502          13 :         checked_icache_flush(pc + 10, sizeof(int32_t) + 6 + 8 + 3 + sizeof(int32_t) + disp, loc);
     503             : 
     504             :         // Patch back the original code.
     505          13 :         patcher_patch_code(pr);
     506             : 
     507          13 :         return true;
     508             : }
     509             : 
     510             : 
     511             : /* patcher_instanceof_interface ************************************************
     512             : 
     513             :    Machine code:
     514             : 
     515             :    <patched call position>
     516             :    45 8b 9a 1c 00 00 00             mov    0x1c(%r10),%r11d
     517             :    41 81 fb 00 00 00 00             cmp    $0x0,%r11d
     518             :    0f 8e 94 04 00 00                jle    0x00002aaaaab018f8
     519             :    4d 8b 9a 00 00 00 00             mov    0x0(%r10),%r11
     520             : 
     521             : *******************************************************************************/
     522             : 
     523          30 : bool patcher_instanceof_interface(patchref_t *pr)
     524             : {
     525          30 :         uint8_t*           pc = (uint8_t*)           pr->mpc;
     526          30 :         constant_classref* cr = (constant_classref*) pr->ref;
     527             : 
     528             :         // Resolve the class.
     529          30 :         classinfo* c = resolve_classref_eager(cr);
     530             : 
     531          30 :         if (c == NULL)
     532           0 :                 return false;
     533             : 
     534          30 :         pc += PATCHER_CALL_SIZE;
     535          30 :         pc += PATCH_ALIGNMENT((uintptr_t) pc, 10, sizeof(int32_t));
     536             : 
     537             :         // Patch super class index.
     538          30 :         patch_checked_location((int32_t*) (pc + 10), c->index);
     539             : 
     540          30 :         int disp = PATCH_ALIGNMENT((uintptr_t) (pc + 7 + 7 + 6), 3, sizeof(int32_t));
     541          30 :         pc += disp;
     542          30 :         int32_t *loc = patch_checked_location((int32_t*) (pc + 7 + 7 + 6 + 3), (int32_t) (OFFSET(vftbl_t, interfacetable[0]) - c->index * sizeof(methodptr*)));
     543             : 
     544             :         // Synchronize instruction cache.
     545          30 :         checked_icache_flush(pc + 10, sizeof(int32_t) + 6 + 3 + sizeof(int32_t) + disp, loc);
     546             : 
     547             :         // Patch back the original code.
     548          30 :         patcher_patch_code(pr);
     549             : 
     550          30 :         return true;
     551             : }
     552             : 
     553             : 
     554             : /*
     555             :  * These are local overrides for various environment variables in Emacs.
     556             :  * Please do not remove this and leave it at the end of the file, where
     557             :  * Emacs will automagically detect them.
     558             :  * ---------------------------------------------------------------------
     559             :  * Local variables:
     560             :  * mode: c++
     561             :  * indent-tabs-mode: t
     562             :  * c-basic-offset: 4
     563             :  * tab-width: 4
     564             :  * End:
     565             :  * vim:noexpandtab:sw=4:ts=4:
     566             :  */

Generated by: LCOV version 1.11