 fc59d2d870
			
		
	
	
		fc59d2d870
		
	
	
	
	
		
			
			qemu_log_lock() now returns a handle and qemu_log_unlock() receives a
handle to unlock.  This allows for changing the handle during logging
and ensures the lock() and unlock() are for the same file.
Also in target/tilegx/translate.c removed the qemu_log_lock()/unlock()
calls (and the log("\n")), since the translator can longjmp out of the
loop if it attempts to translate an instruction in an inaccessible page.
Signed-off-by: Robert Foley <robert.foley@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Message-Id: <20191118211528.3221-5-robert.foley@linaro.org>
		
	
			
		
			
				
	
	
		
			149 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			149 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Generic intermediate code generation.
 | |
|  *
 | |
|  * Copyright (C) 2016-2017 Lluís Vilanova <vilanova@ac.upc.edu>
 | |
|  *
 | |
|  * This work is licensed under the terms of the GNU GPL, version 2 or later.
 | |
|  * See the COPYING file in the top-level directory.
 | |
|  */
 | |
| 
 | |
| #include "qemu/osdep.h"
 | |
| #include "qemu/error-report.h"
 | |
| #include "cpu.h"
 | |
| #include "tcg/tcg.h"
 | |
| #include "tcg/tcg-op.h"
 | |
| #include "exec/exec-all.h"
 | |
| #include "exec/gen-icount.h"
 | |
| #include "exec/log.h"
 | |
| #include "exec/translator.h"
 | |
| #include "exec/plugin-gen.h"
 | |
| 
 | |
| /* Pairs with tcg_clear_temp_count.
 | |
|    To be called by #TranslatorOps.{translate_insn,tb_stop} if
 | |
|    (1) the target is sufficiently clean to support reporting,
 | |
|    (2) as and when all temporaries are known to be consumed.
 | |
|    For most targets, (2) is at the end of translate_insn.  */
 | |
| void translator_loop_temp_check(DisasContextBase *db)
 | |
| {
 | |
|     if (tcg_check_temp_count()) {
 | |
|         qemu_log("warning: TCG temporary leaks before "
 | |
|                  TARGET_FMT_lx "\n", db->pc_next);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
 | |
|                      CPUState *cpu, TranslationBlock *tb, int max_insns)
 | |
| {
 | |
|     int bp_insn = 0;
 | |
|     bool plugin_enabled;
 | |
| 
 | |
|     /* Initialize DisasContext */
 | |
|     db->tb = tb;
 | |
|     db->pc_first = tb->pc;
 | |
|     db->pc_next = db->pc_first;
 | |
|     db->is_jmp = DISAS_NEXT;
 | |
|     db->num_insns = 0;
 | |
|     db->max_insns = max_insns;
 | |
|     db->singlestep_enabled = cpu->singlestep_enabled;
 | |
| 
 | |
|     ops->init_disas_context(db, cpu);
 | |
|     tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
 | |
| 
 | |
|     /* Reset the temp count so that we can identify leaks */
 | |
|     tcg_clear_temp_count();
 | |
| 
 | |
|     /* Start translating.  */
 | |
|     gen_tb_start(db->tb);
 | |
|     ops->tb_start(db, cpu);
 | |
|     tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
 | |
| 
 | |
|     plugin_enabled = plugin_gen_tb_start(cpu, tb);
 | |
| 
 | |
|     while (true) {
 | |
|         db->num_insns++;
 | |
|         ops->insn_start(db, cpu);
 | |
|         tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
 | |
| 
 | |
|         if (plugin_enabled) {
 | |
|             plugin_gen_insn_start(cpu, db);
 | |
|         }
 | |
| 
 | |
|         /* Pass breakpoint hits to target for further processing */
 | |
|         if (!db->singlestep_enabled
 | |
|             && unlikely(!QTAILQ_EMPTY(&cpu->breakpoints))) {
 | |
|             CPUBreakpoint *bp;
 | |
|             QTAILQ_FOREACH(bp, &cpu->breakpoints, entry) {
 | |
|                 if (bp->pc == db->pc_next) {
 | |
|                     if (ops->breakpoint_check(db, cpu, bp)) {
 | |
|                         bp_insn = 1;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             /* The breakpoint_check hook may use DISAS_TOO_MANY to indicate
 | |
|                that only one more instruction is to be executed.  Otherwise
 | |
|                it should use DISAS_NORETURN when generating an exception,
 | |
|                but may use a DISAS_TARGET_* value for Something Else.  */
 | |
|             if (db->is_jmp > DISAS_TOO_MANY) {
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /* Disassemble one instruction.  The translate_insn hook should
 | |
|            update db->pc_next and db->is_jmp to indicate what should be
 | |
|            done next -- either exiting this loop or locate the start of
 | |
|            the next instruction.  */
 | |
|         if (db->num_insns == db->max_insns
 | |
|             && (tb_cflags(db->tb) & CF_LAST_IO)) {
 | |
|             /* Accept I/O on the last instruction.  */
 | |
|             gen_io_start();
 | |
|             ops->translate_insn(db, cpu);
 | |
|         } else {
 | |
|             ops->translate_insn(db, cpu);
 | |
|         }
 | |
| 
 | |
|         /* Stop translation if translate_insn so indicated.  */
 | |
|         if (db->is_jmp != DISAS_NEXT) {
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         /*
 | |
|          * We can't instrument after instructions that change control
 | |
|          * flow although this only really affects post-load operations.
 | |
|          */
 | |
|         if (plugin_enabled) {
 | |
|             plugin_gen_insn_end();
 | |
|         }
 | |
| 
 | |
|         /* Stop translation if the output buffer is full,
 | |
|            or we have executed all of the allowed instructions.  */
 | |
|         if (tcg_op_buf_full() || db->num_insns >= db->max_insns) {
 | |
|             db->is_jmp = DISAS_TOO_MANY;
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* Emit code to exit the TB, as indicated by db->is_jmp.  */
 | |
|     ops->tb_stop(db, cpu);
 | |
|     gen_tb_end(db->tb, db->num_insns - bp_insn);
 | |
| 
 | |
|     if (plugin_enabled) {
 | |
|         plugin_gen_tb_end(cpu);
 | |
|     }
 | |
| 
 | |
|     /* The disas_log hook may use these values rather than recompute.  */
 | |
|     db->tb->size = db->pc_next - db->pc_first;
 | |
|     db->tb->icount = db->num_insns;
 | |
| 
 | |
| #ifdef DEBUG_DISAS
 | |
|     if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)
 | |
|         && qemu_log_in_addr_range(db->pc_first)) {
 | |
|         FILE *logfile = qemu_log_lock();
 | |
|         qemu_log("----------------\n");
 | |
|         ops->disas_log(db, cpu);
 | |
|         qemu_log("\n");
 | |
|         qemu_log_unlock(logfile);
 | |
|     }
 | |
| #endif
 | |
| }
 |