| 1 | /* |
|---|
| 2 | * SOCLIB_LGPL_HEADER_BEGIN |
|---|
| 3 | * |
|---|
| 4 | * This file is part of SoCLib, GNU LGPLv2.1. |
|---|
| 5 | * |
|---|
| 6 | * SoCLib is free software; you can redistribute it and/or modify it |
|---|
| 7 | * under the terms of the GNU Lesser General Public License as published |
|---|
| 8 | * by the Free Software Foundation; version 2.1 of the License. |
|---|
| 9 | * |
|---|
| 10 | * SoCLib is distributed in the hope that it will be useful, but |
|---|
| 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|---|
| 13 | * Lesser General Public License for more details. |
|---|
| 14 | * |
|---|
| 15 | * You should have received a copy of the GNU Lesser General Public |
|---|
| 16 | * License along with SoCLib; if not, write to the Free Software |
|---|
| 17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|---|
| 18 | * 02110-1301 USA |
|---|
| 19 | * |
|---|
| 20 | * SOCLIB_LGPL_HEADER_END |
|---|
| 21 | * |
|---|
| 22 | * Copyright (c) UPMC, Lip6 |
|---|
| 23 | * Nicolas Pouillon <nipo@ssji.net>, 2009 |
|---|
| 24 | * Alexandre Becoulet <alexandre.becoulet@free.fr>, 2010 |
|---|
| 25 | * |
|---|
| 26 | * Maintainers: nipo becoulet |
|---|
| 27 | */ |
|---|
| 28 | |
|---|
| 29 | #include <cstring> |
|---|
| 30 | |
|---|
| 31 | #include <cassert> |
|---|
| 32 | |
|---|
| 33 | #include <stdint.h> |
|---|
| 34 | #include <signal.h> |
|---|
| 35 | |
|---|
| 36 | #include "iss_memchecker_registers.h" |
|---|
| 37 | #include "iss_memchecker.h" |
|---|
| 38 | #include "exception.h" |
|---|
| 39 | |
|---|
| 40 | #include "soclib_endian.h" |
|---|
| 41 | #include "loader.h" |
|---|
| 42 | |
|---|
| 43 | #define MEMCHK_COLOR_WARN(str) "\x1b[93;1m" << str << "\x1b[m" |
|---|
| 44 | #define MEMCHK_COLOR_ERR(str) "\x1b[91;1m" << str << "\x1b[m" |
|---|
| 45 | #define MEMCHK_COLOR_INFOC(str) "\x1b[96;1m" << str << "\x1b[m" |
|---|
| 46 | #define MEMCHK_COLOR_INFOS(str) "\x1b[94;1m" << str << "\x1b[m" |
|---|
| 47 | #define MEMCHK_COLOR_INFOR(str) "\x1b[92;1m" << str << "\x1b[m" |
|---|
| 48 | #define MEMCHK_COLOR_INFOL(str) "\x1b[95;1m" << str << "\x1b[m" |
|---|
| 49 | #define MEMCHK_BOLD(str) "\x1b[1m" << str << "\x1b[m" |
|---|
| 50 | |
|---|
| 51 | namespace soclib { namespace common { |
|---|
| 52 | |
|---|
| 53 | namespace __iss_memchecker { |
|---|
| 54 | |
|---|
| 55 | typedef uint32_t error_level_t; |
|---|
| 56 | |
|---|
| 57 | namespace { |
|---|
| 58 | MemoryState * s_memory_state = NULL; |
|---|
| 59 | } |
|---|
| 60 | |
|---|
| 61 | enum { |
|---|
| 62 | ERROR_NONE = 0, |
|---|
| 63 | ERROR_UNINITIALIZED_WORD = 0x00000001, |
|---|
| 64 | ERROR_INVALID_ACCESS = 0x00000002, |
|---|
| 65 | ERROR_SP_OUTOFBOUNDS = 0x00000004, |
|---|
| 66 | ERROR_FP_OUTOFBOUNDS = 0x00000008, |
|---|
| 67 | ERROR_DATA_ACCESS_BELOW_SP = 0x00000010, |
|---|
| 68 | ERROR_CREATING_STACK_NOT_ALLOC = 0x00000020, |
|---|
| 69 | ERROR_BAD_REGION_REALLOCATION = 0x00000040, |
|---|
| 70 | ERROR_CONTEXT_ON_TWO_CPUS = 0x00000080, |
|---|
| 71 | ERROR_BAD_CONTEXT_DEL = 0x00000100, |
|---|
| 72 | ERROR_BAD_CONTEXT_CREATE = 0x00000200, |
|---|
| 73 | ERROR_BAD_CONTEXT_INVALIDATE = 0x00000400, |
|---|
| 74 | ERROR_BAD_CONTEXT_SWITCH = 0x00000800, |
|---|
| 75 | ERROR_REGION_OVERLAP = 0x00001000, |
|---|
| 76 | ERROR_IRQ_ENABLED_MAGIC = 0x00002000, |
|---|
| 77 | ERROR_IRQ_ENABLED_TMP = 0x00004000, |
|---|
| 78 | ERROR_IRQ_ENABLED_LOCK = 0x00008000, |
|---|
| 79 | ERROR_LOCK_DEAD_LOCK = 0x00010000, |
|---|
| 80 | ERROR_NULL_POINTER_ACCESS = 0x00020000, |
|---|
| 81 | ERROR_BAD_MAGIC_OP = 0x00040000, |
|---|
| 82 | ERROR_IRQ_DISABLED_USER = 0x00080000, |
|---|
| 83 | }; |
|---|
| 84 | |
|---|
| 85 | // errors which use a repeat mask to avoid flooding output |
|---|
| 86 | static const uint32_t repeat_filter = ( ERROR_IRQ_ENABLED_LOCK | |
|---|
| 87 | ERROR_SP_OUTOFBOUNDS | |
|---|
| 88 | ERROR_FP_OUTOFBOUNDS | |
|---|
| 89 | ERROR_IRQ_ENABLED_TMP | |
|---|
| 90 | ERROR_IRQ_DISABLED_USER | |
|---|
| 91 | ERROR_LOCK_DEAD_LOCK); |
|---|
| 92 | |
|---|
| 93 | class ContextState |
|---|
| 94 | { |
|---|
| 95 | const uint32_t m_id; |
|---|
| 96 | uint32_t m_running_on; |
|---|
| 97 | static const uint32_t s_not_running = (uint32_t)-1; |
|---|
| 98 | uint32_t m_refcount; |
|---|
| 99 | bool m_valid; |
|---|
| 100 | bool m_tmp; |
|---|
| 101 | |
|---|
| 102 | public: |
|---|
| 103 | const uint64_t m_stack_lower; |
|---|
| 104 | const uint64_t m_stack_upper; |
|---|
| 105 | |
|---|
| 106 | ContextState( uint32_t id, uint32_t stack_low, uint32_t stack_up, bool tmp = false ) |
|---|
| 107 | : m_id(id), |
|---|
| 108 | m_running_on(s_not_running), |
|---|
| 109 | m_refcount(0), |
|---|
| 110 | m_valid(true), |
|---|
| 111 | m_tmp(tmp), |
|---|
| 112 | m_stack_lower(stack_low), |
|---|
| 113 | m_stack_upper(stack_up ? stack_up : ((uint64_t)1<<32)) |
|---|
| 114 | { |
|---|
| 115 | assert(m_stack_lower <= m_stack_upper && "Stack upside down"); |
|---|
| 116 | #if defined(SOCLIB_MODULE_DEBUG) |
|---|
| 117 | std::cout << "Creating new context " << *this << std::endl; |
|---|
| 118 | #endif |
|---|
| 119 | } |
|---|
| 120 | |
|---|
| 121 | ~ContextState() |
|---|
| 122 | { |
|---|
| 123 | #if defined(SOCLIB_MODULE_DEBUG) |
|---|
| 124 | std::cout << "Deleting context " << *this << std::endl; |
|---|
| 125 | #endif |
|---|
| 126 | } |
|---|
| 127 | |
|---|
| 128 | inline bool valid() const |
|---|
| 129 | { |
|---|
| 130 | return m_valid; |
|---|
| 131 | } |
|---|
| 132 | |
|---|
| 133 | inline bool temporary() const |
|---|
| 134 | { |
|---|
| 135 | return m_tmp; |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | inline void invalidate() |
|---|
| 139 | { |
|---|
| 140 | m_valid = false; |
|---|
| 141 | } |
|---|
| 142 | |
|---|
| 143 | inline bool stack_contains( uint64_t sp ) const |
|---|
| 144 | { |
|---|
| 145 | return (m_stack_lower < sp && sp <= m_stack_upper); |
|---|
| 146 | } |
|---|
| 147 | |
|---|
| 148 | inline bool is( uint32_t id ) const |
|---|
| 149 | { |
|---|
| 150 | return m_id == id; |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | inline uint32_t id() const |
|---|
| 154 | { |
|---|
| 155 | return m_id; |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | inline error_level_t schedule( uint32_t cpu ) |
|---|
| 159 | { |
|---|
| 160 | error_level_t r = 0; |
|---|
| 161 | if ( m_running_on != s_not_running ) |
|---|
| 162 | r |= ERROR_CONTEXT_ON_TWO_CPUS; |
|---|
| 163 | m_running_on = cpu; |
|---|
| 164 | return r; |
|---|
| 165 | } |
|---|
| 166 | |
|---|
| 167 | inline void unschedule() |
|---|
| 168 | { |
|---|
| 169 | m_running_on = s_not_running; |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | bool overlaps( ContextState &other ) const |
|---|
| 173 | { |
|---|
| 174 | return overlaps( |
|---|
| 175 | other.m_stack_lower, |
|---|
| 176 | other.m_stack_upper ); |
|---|
| 177 | } |
|---|
| 178 | |
|---|
| 179 | bool overlaps( uint64_t base, uint64_t end ) const |
|---|
| 180 | { |
|---|
| 181 | if ( end <= m_stack_lower ) |
|---|
| 182 | return false; |
|---|
| 183 | if ( m_stack_upper <= base ) |
|---|
| 184 | return false; |
|---|
| 185 | return true; |
|---|
| 186 | } |
|---|
| 187 | |
|---|
| 188 | void print( std::ostream &o ) const |
|---|
| 189 | { |
|---|
| 190 | o << "Context #" << std::hex << std::showbase << m_id |
|---|
| 191 | << ", with " << m_stack_lower << "-" << m_stack_upper << " stack range"; |
|---|
| 192 | } |
|---|
| 193 | |
|---|
| 194 | friend std::ostream &operator << (std::ostream &o, const ContextState &cs) |
|---|
| 195 | { |
|---|
| 196 | cs.print(o); |
|---|
| 197 | return o; |
|---|
| 198 | } |
|---|
| 199 | |
|---|
| 200 | void ref() |
|---|
| 201 | { |
|---|
| 202 | ++m_refcount; |
|---|
| 203 | } |
|---|
| 204 | void unref() |
|---|
| 205 | { |
|---|
| 206 | if ( --m_refcount == 0 ) { |
|---|
| 207 | #if defined(SOCLIB_MODULE_DEBUG) |
|---|
| 208 | std::cout << *this << " has not more refs, del" << std::endl; |
|---|
| 209 | #endif |
|---|
| 210 | delete this; |
|---|
| 211 | } |
|---|
| 212 | } |
|---|
| 213 | }; |
|---|
| 214 | |
|---|
| 215 | class RegionInfo |
|---|
| 216 | { |
|---|
| 217 | public: |
|---|
| 218 | enum State { |
|---|
| 219 | REGION_INVALID = 1, |
|---|
| 220 | REGION_STATE_GLOBAL = 2, |
|---|
| 221 | REGION_STATE_GLOBAL_READ_ONLY = 4, |
|---|
| 222 | REGION_STATE_ALLOCATED = 8, |
|---|
| 223 | REGION_STATE_FREE = 16, |
|---|
| 224 | REGION_STATE_STACK = 32, |
|---|
| 225 | REGION_STATE_WAS_STACK = 64, |
|---|
| 226 | REGION_STATE_PERIPHERAL = 128, |
|---|
| 227 | REGION_STATE_RAW = 256, |
|---|
| 228 | }; |
|---|
| 229 | |
|---|
| 230 | private: |
|---|
| 231 | enum State m_state; |
|---|
| 232 | uint32_t m_at; |
|---|
| 233 | uint32_t m_refcount; |
|---|
| 234 | uint64_t m_base_addr; |
|---|
| 235 | uint64_t m_end_addr; |
|---|
| 236 | RegionInfo *m_previous_state; |
|---|
| 237 | |
|---|
| 238 | public: |
|---|
| 239 | RegionInfo *get_updated_region( enum State state, uint32_t at, uint64_t base_addr, uint64_t end_addr ) |
|---|
| 240 | { |
|---|
| 241 | RegionInfo *n = new RegionInfo( state, at, base_addr, end_addr, this ); |
|---|
| 242 | return n; |
|---|
| 243 | } |
|---|
| 244 | |
|---|
| 245 | RegionInfo( enum State state, uint32_t at, uint64_t base_addr, uint64_t end_addr, RegionInfo *previous_state = 0 ) |
|---|
| 246 | : m_state(state), |
|---|
| 247 | m_at(at), |
|---|
| 248 | m_refcount(0), |
|---|
| 249 | m_base_addr(base_addr), |
|---|
| 250 | m_end_addr(end_addr), |
|---|
| 251 | m_previous_state(previous_state) |
|---|
| 252 | { |
|---|
| 253 | if ( m_previous_state ) |
|---|
| 254 | m_previous_state->ref(); |
|---|
| 255 | #if defined(SOCLIB_MODULE_DEBUG) |
|---|
| 256 | std::cout << "Creating a new region info " << *this |
|---|
| 257 | << std::endl; |
|---|
| 258 | #endif |
|---|
| 259 | } |
|---|
| 260 | |
|---|
| 261 | ~RegionInfo() |
|---|
| 262 | { |
|---|
| 263 | if ( m_previous_state ) |
|---|
| 264 | m_previous_state->unref(); |
|---|
| 265 | } |
|---|
| 266 | |
|---|
| 267 | bool new_state_valid( enum State new_state ) |
|---|
| 268 | { |
|---|
| 269 | int valid_new_states = 0; |
|---|
| 270 | switch(m_state) { |
|---|
| 271 | case REGION_INVALID: |
|---|
| 272 | valid_new_states = 0; |
|---|
| 273 | break; |
|---|
| 274 | case REGION_STATE_GLOBAL: |
|---|
| 275 | valid_new_states = |
|---|
| 276 | REGION_STATE_FREE | |
|---|
| 277 | REGION_STATE_STACK; |
|---|
| 278 | break; |
|---|
| 279 | case REGION_STATE_GLOBAL_READ_ONLY: |
|---|
| 280 | valid_new_states = 0; |
|---|
| 281 | break; |
|---|
| 282 | case REGION_STATE_ALLOCATED: |
|---|
| 283 | valid_new_states = |
|---|
| 284 | REGION_STATE_FREE | |
|---|
| 285 | REGION_STATE_STACK; |
|---|
| 286 | break; |
|---|
| 287 | case REGION_STATE_FREE: |
|---|
| 288 | valid_new_states = |
|---|
| 289 | REGION_STATE_FREE | |
|---|
| 290 | REGION_STATE_ALLOCATED; |
|---|
| 291 | break; |
|---|
| 292 | case REGION_STATE_PERIPHERAL: |
|---|
| 293 | valid_new_states = 0; |
|---|
| 294 | break; |
|---|
| 295 | case REGION_STATE_STACK: |
|---|
| 296 | valid_new_states = |
|---|
| 297 | REGION_STATE_WAS_STACK; |
|---|
| 298 | break; |
|---|
| 299 | case REGION_STATE_WAS_STACK: |
|---|
| 300 | valid_new_states = |
|---|
| 301 | REGION_STATE_FREE | |
|---|
| 302 | REGION_STATE_STACK; |
|---|
| 303 | break; |
|---|
| 304 | case REGION_STATE_RAW: |
|---|
| 305 | valid_new_states = |
|---|
| 306 | REGION_STATE_PERIPHERAL | |
|---|
| 307 | REGION_STATE_GLOBAL | |
|---|
| 308 | REGION_STATE_FREE; |
|---|
| 309 | break; |
|---|
| 310 | } |
|---|
| 311 | return valid_new_states & new_state; |
|---|
| 312 | } |
|---|
| 313 | |
|---|
| 314 | bool contains( uint64_t addr ) const |
|---|
| 315 | { |
|---|
| 316 | return m_base_addr <= addr && addr < m_end_addr; |
|---|
| 317 | } |
|---|
| 318 | |
|---|
| 319 | State state() const |
|---|
| 320 | { |
|---|
| 321 | return m_state; |
|---|
| 322 | } |
|---|
| 323 | |
|---|
| 324 | void ref() |
|---|
| 325 | { |
|---|
| 326 | ++m_refcount; |
|---|
| 327 | } |
|---|
| 328 | void unref() |
|---|
| 329 | { |
|---|
| 330 | if ( --m_refcount == 0 ) |
|---|
| 331 | delete this; |
|---|
| 332 | } |
|---|
| 333 | |
|---|
| 334 | error_level_t do_write() const |
|---|
| 335 | { |
|---|
| 336 | if ( m_state == REGION_STATE_GLOBAL_READ_ONLY ) |
|---|
| 337 | return ERROR_INVALID_ACCESS; |
|---|
| 338 | return do_read(); |
|---|
| 339 | } |
|---|
| 340 | |
|---|
| 341 | error_level_t do_read() const |
|---|
| 342 | { |
|---|
| 343 | if ( m_state & |
|---|
| 344 | ( REGION_STATE_FREE |
|---|
| 345 | | REGION_INVALID |
|---|
| 346 | | REGION_STATE_WAS_STACK ) |
|---|
| 347 | ) |
|---|
| 348 | return ERROR_INVALID_ACCESS; |
|---|
| 349 | return ERROR_NONE; |
|---|
| 350 | } |
|---|
| 351 | |
|---|
| 352 | static const char *state_str(State state) |
|---|
| 353 | { |
|---|
| 354 | switch (state) { |
|---|
| 355 | case REGION_INVALID: return "invalid"; |
|---|
| 356 | case REGION_STATE_GLOBAL: return "global"; |
|---|
| 357 | case REGION_STATE_GLOBAL_READ_ONLY: return "global read only"; |
|---|
| 358 | case REGION_STATE_ALLOCATED: return "allocated"; |
|---|
| 359 | case REGION_STATE_FREE: return "free"; |
|---|
| 360 | case REGION_STATE_PERIPHERAL: return "devices"; |
|---|
| 361 | case REGION_STATE_STACK: return "stack"; |
|---|
| 362 | case REGION_STATE_WAS_STACK: return "former stack"; |
|---|
| 363 | case REGION_STATE_RAW: return "raw"; |
|---|
| 364 | default: return "unknown"; |
|---|
| 365 | } |
|---|
| 366 | } |
|---|
| 367 | |
|---|
| 368 | const char *state_str() const |
|---|
| 369 | { |
|---|
| 370 | return state_str(m_state); |
|---|
| 371 | } |
|---|
| 372 | |
|---|
| 373 | void print( std::ostream &o ) const |
|---|
| 374 | { |
|---|
| 375 | o << "Region " << std::hex |
|---|
| 376 | // << "at " << m_at << " " |
|---|
| 377 | << m_base_addr << "-" << m_end_addr << " : " << state_str(); |
|---|
| 378 | o << " memory"; |
|---|
| 379 | } |
|---|
| 380 | |
|---|
| 381 | RegionInfo *prev_state() const |
|---|
| 382 | { |
|---|
| 383 | return m_previous_state; |
|---|
| 384 | } |
|---|
| 385 | |
|---|
| 386 | friend std::ostream &operator << (std::ostream &o, const RegionInfo &ri) |
|---|
| 387 | { |
|---|
| 388 | ri.print(o); |
|---|
| 389 | return o; |
|---|
| 390 | } |
|---|
| 391 | }; |
|---|
| 392 | |
|---|
| 393 | class AddressInfo |
|---|
| 394 | { |
|---|
| 395 | RegionInfo *m_info; |
|---|
| 396 | static const uintptr_t s_initialized_bit = 1; |
|---|
| 397 | static const uintptr_t s_islock_bit = 2; |
|---|
| 398 | static const uintptr_t s_addr_mask = ~(uintptr_t)3; |
|---|
| 399 | |
|---|
| 400 | public: |
|---|
| 401 | |
|---|
| 402 | bool is_initialized() const |
|---|
| 403 | { |
|---|
| 404 | return (uintptr_t)m_info & s_initialized_bit; |
|---|
| 405 | } |
|---|
| 406 | |
|---|
| 407 | bool is_spinlock() const |
|---|
| 408 | { |
|---|
| 409 | return (uintptr_t)m_info & s_islock_bit; |
|---|
| 410 | } |
|---|
| 411 | |
|---|
| 412 | void set_initialized( bool initialized ) |
|---|
| 413 | { |
|---|
| 414 | if ( initialized ) |
|---|
| 415 | m_info = (RegionInfo*)((uintptr_t)m_info | s_initialized_bit); |
|---|
| 416 | else |
|---|
| 417 | m_info = (RegionInfo*)((uintptr_t)m_info & ~s_initialized_bit); |
|---|
| 418 | } |
|---|
| 419 | |
|---|
| 420 | void set_spinlock( bool islock ) |
|---|
| 421 | { |
|---|
| 422 | if ( islock ) |
|---|
| 423 | m_info = (RegionInfo*)((uintptr_t)m_info | s_islock_bit); |
|---|
| 424 | else |
|---|
| 425 | m_info = (RegionInfo*)((uintptr_t)m_info & ~s_islock_bit); |
|---|
| 426 | } |
|---|
| 427 | |
|---|
| 428 | RegionInfo *region() const |
|---|
| 429 | { |
|---|
| 430 | return (RegionInfo*)((uintptr_t)m_info & s_addr_mask); |
|---|
| 431 | } |
|---|
| 432 | |
|---|
| 433 | error_level_t region_set( RegionInfo *ptr ) |
|---|
| 434 | { |
|---|
| 435 | bool r = false; |
|---|
| 436 | assert(ptr); |
|---|
| 437 | ptr->ref(); |
|---|
| 438 | |
|---|
| 439 | if ( region() ) { |
|---|
| 440 | if ( region()->new_state_valid(ptr->state()) ) |
|---|
| 441 | region()->unref(); |
|---|
| 442 | else |
|---|
| 443 | r = true; |
|---|
| 444 | } |
|---|
| 445 | m_info = (RegionInfo*)( |
|---|
| 446 | ((uintptr_t)ptr & s_addr_mask) | |
|---|
| 447 | ((uintptr_t)m_info & ~s_addr_mask)); |
|---|
| 448 | return r; |
|---|
| 449 | } |
|---|
| 450 | |
|---|
| 451 | AddressInfo & operator=( const AddressInfo &ref ) |
|---|
| 452 | { |
|---|
| 453 | if ( &ref == this ) |
|---|
| 454 | return *this; |
|---|
| 455 | region_set(ref.region()); |
|---|
| 456 | set_initialized(false); |
|---|
| 457 | } |
|---|
| 458 | |
|---|
| 459 | AddressInfo( RegionInfo *ri, bool initialized = false ) |
|---|
| 460 | : m_info(0) |
|---|
| 461 | { |
|---|
| 462 | region_set(ri); |
|---|
| 463 | set_initialized(initialized); |
|---|
| 464 | } |
|---|
| 465 | |
|---|
| 466 | AddressInfo() |
|---|
| 467 | : m_info(0) |
|---|
| 468 | {} |
|---|
| 469 | |
|---|
| 470 | ~AddressInfo() |
|---|
| 471 | { |
|---|
| 472 | if ( region() ) |
|---|
| 473 | region()->unref(); |
|---|
| 474 | } |
|---|
| 475 | |
|---|
| 476 | AddressInfo( const AddressInfo &ref ) |
|---|
| 477 | : m_info(0) |
|---|
| 478 | { |
|---|
| 479 | if ( ref.region() ) |
|---|
| 480 | region_set(ref.region()); |
|---|
| 481 | } |
|---|
| 482 | |
|---|
| 483 | error_level_t do_write() |
|---|
| 484 | { |
|---|
| 485 | set_initialized(true); |
|---|
| 486 | return ERROR_NONE; |
|---|
| 487 | } |
|---|
| 488 | |
|---|
| 489 | error_level_t do_read() |
|---|
| 490 | { |
|---|
| 491 | if ( ! is_initialized() && |
|---|
| 492 | ! (m_info->state() & RegionInfo::REGION_STATE_PERIPHERAL) ) |
|---|
| 493 | return ERROR_UNINITIALIZED_WORD; |
|---|
| 494 | set_initialized(true); |
|---|
| 495 | return ERROR_NONE; |
|---|
| 496 | } |
|---|
| 497 | |
|---|
| 498 | void print( std::ostream &o ) const |
|---|
| 499 | { |
|---|
| 500 | o << "<AddressInfo " << std::dec |
|---|
| 501 | << (is_initialized() ? " initialized" : " uninitialized"); |
|---|
| 502 | if ( region() ) |
|---|
| 503 | o << ", " << *region(); |
|---|
| 504 | else |
|---|
| 505 | o << ", no region"; |
|---|
| 506 | o << ">"; |
|---|
| 507 | } |
|---|
| 508 | |
|---|
| 509 | friend std::ostream &operator << (std::ostream &o, const AddressInfo &ai) |
|---|
| 510 | { |
|---|
| 511 | ai.print(o); |
|---|
| 512 | return o; |
|---|
| 513 | } |
|---|
| 514 | }; |
|---|
| 515 | |
|---|
| 516 | class MemoryState |
|---|
| 517 | { |
|---|
| 518 | Loader m_binary; |
|---|
| 519 | |
|---|
| 520 | typedef std::map<uint64_t, ContextState *> context_map_t; |
|---|
| 521 | typedef std::map<uint64_t, std::vector<AddressInfo> *> region_map_t; |
|---|
| 522 | context_map_t m_contexts; |
|---|
| 523 | region_map_t m_regions; |
|---|
| 524 | AddressInfo m_default_address; |
|---|
| 525 | uintptr_t m_comm_address; |
|---|
| 526 | |
|---|
| 527 | public: |
|---|
| 528 | ContextState * const unknown_context; |
|---|
| 529 | |
|---|
| 530 | MemoryState( const soclib::common::MappingTable &mt, |
|---|
| 531 | const soclib::common::Loader &loader, |
|---|
| 532 | const std::string &exclusions ) |
|---|
| 533 | : m_binary(loader), |
|---|
| 534 | m_contexts(), |
|---|
| 535 | m_regions(), |
|---|
| 536 | m_default_address(new RegionInfo(RegionInfo::REGION_INVALID, 0, 0, 0), true), |
|---|
| 537 | m_comm_address(0x400), |
|---|
| 538 | unknown_context(new ContextState(ISS_MEMCHECKER_ID_UNKNOWN, 0, 0 )) //(uint32_t)-1 )) |
|---|
| 539 | { |
|---|
| 540 | unknown_context->ref(); |
|---|
| 541 | |
|---|
| 542 | const std::list<Segment> &segments = mt.getAllSegmentList(); |
|---|
| 543 | Loader::section_list_t sections = loader.sections(); |
|---|
| 544 | |
|---|
| 545 | std::string exclusion_list = ","; |
|---|
| 546 | exclusion_list += exclusions + ","; |
|---|
| 547 | |
|---|
| 548 | for ( std::list<Segment>::const_iterator i = segments.begin(); |
|---|
| 549 | i != segments.end(); |
|---|
| 550 | ++i ) { |
|---|
| 551 | |
|---|
| 552 | RegionInfo *ri = new RegionInfo( |
|---|
| 553 | RegionInfo::REGION_STATE_RAW, 0, |
|---|
| 554 | i->baseAddress(), (uint64_t)i->baseAddress() + i->size() ); |
|---|
| 555 | std::vector<AddressInfo> *rm = new std::vector<AddressInfo>( i->size() / 4 ); |
|---|
| 556 | |
|---|
| 557 | for ( size_t j=0; j<i->size()/4; ++j ) |
|---|
| 558 | (*rm)[j].region_set(ri); |
|---|
| 559 | |
|---|
| 560 | m_regions[i->baseAddress()] = rm; |
|---|
| 561 | } |
|---|
| 562 | |
|---|
| 563 | for ( Loader::section_list_t::const_iterator i = sections.begin(); |
|---|
| 564 | i != sections.end(); |
|---|
| 565 | ++i ) { |
|---|
| 566 | |
|---|
| 567 | #if defined( SOCLIB_MODULE_DEBUG ) |
|---|
| 568 | std::cout << "Creating a region info for" |
|---|
| 569 | << " " << i->name() |
|---|
| 570 | << " @" << std::hex << i->lma() |
|---|
| 571 | << ", " << std::dec << i->size() << " bytes long" |
|---|
| 572 | << " flags: " << (i->flag_read_only() ? "RO" : "") |
|---|
| 573 | << std::endl; |
|---|
| 574 | #endif |
|---|
| 575 | |
|---|
| 576 | RegionInfo::State state = RegionInfo::REGION_STATE_GLOBAL; |
|---|
| 577 | if ( i->flag_read_only() ) |
|---|
| 578 | state = RegionInfo::REGION_STATE_GLOBAL_READ_ONLY; |
|---|
| 579 | |
|---|
| 580 | region_new_state( state, 0, i->lma(), i->size() ); |
|---|
| 581 | // if ( i->has_data() ) |
|---|
| 582 | for ( size_t j=0; j<i->size(); j+=4 ) |
|---|
| 583 | info_for_address( (uint64_t)i->lma()+j )->do_write(); |
|---|
| 584 | } |
|---|
| 585 | |
|---|
| 586 | for ( std::list<Segment>::const_iterator i = segments.begin(); |
|---|
| 587 | i != segments.end(); |
|---|
| 588 | ++i ) { |
|---|
| 589 | std::string vname = std::string(",")+i->name()+","; |
|---|
| 590 | |
|---|
| 591 | if ( exclusion_list.find(vname) == std::string::npos ) |
|---|
| 592 | continue; |
|---|
| 593 | |
|---|
| 594 | region_update_state( RegionInfo::REGION_STATE_PERIPHERAL, 0, i->baseAddress(), i->size() ); |
|---|
| 595 | } |
|---|
| 596 | |
|---|
| 597 | const BinaryFileSymbol *sym = loader.get_symbol_by_name( "soclib_iss_memchecker_addr" ); |
|---|
| 598 | if ( sym ) { |
|---|
| 599 | m_comm_address = sym->address(); |
|---|
| 600 | std::cout << "Binary file defined IssMemchecker communication address to " |
|---|
| 601 | << m_comm_address << std::endl; |
|---|
| 602 | } |
|---|
| 603 | } |
|---|
| 604 | |
|---|
| 605 | uintptr_t comm_address() const |
|---|
| 606 | { |
|---|
| 607 | return m_comm_address; |
|---|
| 608 | } |
|---|
| 609 | |
|---|
| 610 | ContextState *context_get( uint32_t id ) const |
|---|
| 611 | { |
|---|
| 612 | context_map_t::const_iterator i = m_contexts.find(id); |
|---|
| 613 | if ( i != m_contexts.end() ) |
|---|
| 614 | return i->second; |
|---|
| 615 | else |
|---|
| 616 | return unknown_context; |
|---|
| 617 | } |
|---|
| 618 | |
|---|
| 619 | bool context_create( uint32_t id, ContextState *context ) |
|---|
| 620 | { |
|---|
| 621 | context_map_t::const_iterator i = m_contexts.find(id); |
|---|
| 622 | |
|---|
| 623 | if ( i != m_contexts.end() ) { |
|---|
| 624 | return false; |
|---|
| 625 | } |
|---|
| 626 | |
|---|
| 627 | for ( context_map_t::const_iterator i = m_contexts.begin(); |
|---|
| 628 | i != m_contexts.end(); |
|---|
| 629 | ++i ) { |
|---|
| 630 | #if defined(SOCLIB_MODULE_DEBUG) |
|---|
| 631 | std::cout << "Checking " << *context << " and " << *i->second << std::endl; |
|---|
| 632 | #endif |
|---|
| 633 | if ( context->overlaps( *i->second ) ) { |
|---|
| 634 | std::cout << "Context " << *context << " overlaps " << *i->second << std::endl; |
|---|
| 635 | abort(); |
|---|
| 636 | } |
|---|
| 637 | } |
|---|
| 638 | m_contexts[id] = context; |
|---|
| 639 | context->ref(); |
|---|
| 640 | return true; |
|---|
| 641 | } |
|---|
| 642 | |
|---|
| 643 | bool context_delete( uint32_t id ) |
|---|
| 644 | { |
|---|
| 645 | if ( id == ISS_MEMCHECKER_ID_UNKNOWN ) { |
|---|
| 646 | return false; |
|---|
| 647 | } |
|---|
| 648 | |
|---|
| 649 | context_map_t::iterator i = m_contexts.find(id); |
|---|
| 650 | |
|---|
| 651 | if (i == m_contexts.end()) { |
|---|
| 652 | return false; |
|---|
| 653 | } |
|---|
| 654 | |
|---|
| 655 | i->second->unref(); |
|---|
| 656 | m_contexts.erase(i); |
|---|
| 657 | return true; |
|---|
| 658 | } |
|---|
| 659 | |
|---|
| 660 | bool context_invalidate( uint32_t id ) |
|---|
| 661 | { |
|---|
| 662 | context_map_t::iterator i = m_contexts.find(id); |
|---|
| 663 | |
|---|
| 664 | if (i == m_contexts.end()) { |
|---|
| 665 | return false; |
|---|
| 666 | } |
|---|
| 667 | |
|---|
| 668 | for ( uint64_t addr = i->second->m_stack_lower; addr < i->second->m_stack_upper; addr+= 4 ) { |
|---|
| 669 | AddressInfo *ai = s_memory_state->info_for_address(addr); |
|---|
| 670 | ai->set_initialized(false); |
|---|
| 671 | } |
|---|
| 672 | |
|---|
| 673 | i->second->invalidate(); |
|---|
| 674 | |
|---|
| 675 | return true; |
|---|
| 676 | } |
|---|
| 677 | |
|---|
| 678 | AddressInfo *info_for_address(uint64_t address) |
|---|
| 679 | { |
|---|
| 680 | region_map_t::iterator i = m_regions.upper_bound(address); |
|---|
| 681 | |
|---|
| 682 | #if defined(SOCLIB_MODULE_DEBUG) |
|---|
| 683 | std::cout |
|---|
| 684 | << "info_for_address(" << std::hex << address << "): " << i->first << " is_end: " << (i == m_regions.end()) << std::endl; |
|---|
| 685 | #endif |
|---|
| 686 | |
|---|
| 687 | if ( ! ( i == m_regions.end() && (--i)->first <= address ) ) |
|---|
| 688 | ++i; |
|---|
| 689 | |
|---|
| 690 | while ( i != m_regions.begin() |
|---|
| 691 | && i->first > address ) |
|---|
| 692 | --i; |
|---|
| 693 | |
|---|
| 694 | if ( i == m_regions.end() ) { |
|---|
| 695 | #if defined(SOCLIB_MODULE_DEBUG) |
|---|
| 696 | std::cout |
|---|
| 697 | << "Address " << std::hex << address << " in no region." << std::endl |
|---|
| 698 | << "Regions: " << std::endl; |
|---|
| 699 | for ( region_map_t::iterator i = m_regions.begin(); |
|---|
| 700 | i != m_regions.end(); |
|---|
| 701 | ++i ) |
|---|
| 702 | std::cout << " " << i->first << " size: " << i->second->size() << " words" << std::endl; |
|---|
| 703 | #endif |
|---|
| 704 | |
|---|
| 705 | //abort(); |
|---|
| 706 | return &m_default_address; |
|---|
| 707 | } |
|---|
| 708 | uint64_t region_base = i->first; |
|---|
| 709 | uint64_t word_no = (address-region_base)/4; |
|---|
| 710 | std::vector<AddressInfo> &r = *(i->second); |
|---|
| 711 | if ( region_base <= address && word_no < r.size() ) |
|---|
| 712 | return &r[word_no]; |
|---|
| 713 | #if defined(SOCLIB_MODULE_DEBUG) |
|---|
| 714 | std::cout << "Warning: address " << std::hex << address |
|---|
| 715 | << " " << std::dec << (r.size()-word_no) << " words beyond " |
|---|
| 716 | << r[r.size()-1] << std::endl; |
|---|
| 717 | #endif |
|---|
| 718 | |
|---|
| 719 | return &m_default_address; |
|---|
| 720 | } |
|---|
| 721 | |
|---|
| 722 | error_level_t region_update_state( RegionInfo::State new_state, uint32_t at, uint64_t addr, |
|---|
| 723 | uint64_t size, RegionInfo ** lrt = 0, uint32_t *lat = 0) |
|---|
| 724 | { |
|---|
| 725 | error_level_t r = 0; |
|---|
| 726 | RegionInfo *lri = info_for_address(addr)->region(); |
|---|
| 727 | RegionInfo *nri = lri->get_updated_region( new_state, at, addr, addr+size ); |
|---|
| 728 | |
|---|
| 729 | #if defined(SOCLIB_MODULE_DEBUG) |
|---|
| 730 | std::cout << "Updating " << *lri << " to " << *nri << std::endl; |
|---|
| 731 | #endif |
|---|
| 732 | |
|---|
| 733 | for ( context_map_t::const_iterator i = m_contexts.begin(); |
|---|
| 734 | i != m_contexts.end(); |
|---|
| 735 | ++i ) { |
|---|
| 736 | if ( i->second->overlaps( addr, addr+size ) ) { |
|---|
| 737 | std::cout |
|---|
| 738 | << "Region " << *nri |
|---|
| 739 | << " overlaps " << *(i->second) |
|---|
| 740 | << std::endl; |
|---|
| 741 | |
|---|
| 742 | r = ERROR_REGION_OVERLAP; |
|---|
| 743 | } |
|---|
| 744 | } |
|---|
| 745 | |
|---|
| 746 | for ( uint64_t a = addr; a < addr+size; a+=4 ) { |
|---|
| 747 | AddressInfo *ai = info_for_address(a); |
|---|
| 748 | RegionInfo *ri = ai->region(); |
|---|
| 749 | if ( ai->region_set(nri) && !r ) { |
|---|
| 750 | r = ERROR_BAD_REGION_REALLOCATION; |
|---|
| 751 | if ( lat ) |
|---|
| 752 | *lat = a; |
|---|
| 753 | if ( lrt ) |
|---|
| 754 | *lrt = ri; |
|---|
| 755 | } |
|---|
| 756 | } |
|---|
| 757 | return r; |
|---|
| 758 | } |
|---|
| 759 | |
|---|
| 760 | void region_new_state( RegionInfo::State new_state, uint32_t at, uint64_t addr, uint64_t size ) |
|---|
| 761 | { |
|---|
| 762 | RegionInfo *nri = new RegionInfo( new_state, at, addr, addr+size ); |
|---|
| 763 | for ( uint64_t a = addr; a < addr+size; a+=4 ) |
|---|
| 764 | info_for_address(a)->region_set(nri); |
|---|
| 765 | } |
|---|
| 766 | |
|---|
| 767 | BinaryFileSymbolOffset get_symbol( uintptr_t addr ) const |
|---|
| 768 | { |
|---|
| 769 | return m_binary.get_symbol_by_addr(addr); |
|---|
| 770 | } |
|---|
| 771 | }; |
|---|
| 772 | |
|---|
| 773 | } // namespace __iss_memchecker |
|---|
| 774 | |
|---|
| 775 | using namespace __iss_memchecker; |
|---|
| 776 | |
|---|
| 777 | |
|---|
| 778 | template<typename iss_t> |
|---|
| 779 | uint32_t IssMemchecker<iss_t>::get_cpu_sp() const |
|---|
| 780 | { |
|---|
| 781 | return iss_t::debugGetRegisterValue(m_sp_reg_id); |
|---|
| 782 | } |
|---|
| 783 | |
|---|
| 784 | template<typename iss_t> |
|---|
| 785 | uint32_t IssMemchecker<iss_t>::get_cpu_fp() const |
|---|
| 786 | { |
|---|
| 787 | return iss_t::debugGetRegisterValue(m_fp_reg_id); |
|---|
| 788 | } |
|---|
| 789 | |
|---|
| 790 | template<typename iss_t> |
|---|
| 791 | uint32_t IssMemchecker<iss_t>::get_cpu_pc() const |
|---|
| 792 | { |
|---|
| 793 | return iss_t::debugGetRegisterValue(iss_t::s_pc_register_no); |
|---|
| 794 | } |
|---|
| 795 | |
|---|
| 796 | |
|---|
| 797 | template<typename iss_t> |
|---|
| 798 | void IssMemchecker<iss_t>::init( const soclib::common::MappingTable &mt, |
|---|
| 799 | const soclib::common::Loader &loader, |
|---|
| 800 | const std::string &exclusions ) |
|---|
| 801 | { |
|---|
| 802 | if ( s_memory_state == NULL ) |
|---|
| 803 | s_memory_state = new MemoryState( mt, loader, exclusions ); |
|---|
| 804 | } |
|---|
| 805 | |
|---|
| 806 | template<typename iss_t> |
|---|
| 807 | IssMemchecker<iss_t>::IssMemchecker(const std::string &name, uint32_t ident) |
|---|
| 808 | : iss_t(name, ident), |
|---|
| 809 | m_last_region_touched(0), |
|---|
| 810 | m_has_data_answer(false), |
|---|
| 811 | m_cpuid(ident), |
|---|
| 812 | m_enabled_checks(0), |
|---|
| 813 | m_r1(0), |
|---|
| 814 | m_r2(0), |
|---|
| 815 | m_last_sp(0), |
|---|
| 816 | m_opt_dump_iss(false), |
|---|
| 817 | m_opt_dump_access(false), |
|---|
| 818 | m_opt_show_enable(false), |
|---|
| 819 | m_opt_show_ctx(false), |
|---|
| 820 | m_opt_show_ctxsw(false), |
|---|
| 821 | m_opt_show_region(false), |
|---|
| 822 | m_opt_show_lockops(false), |
|---|
| 823 | m_opt_exit_on_error(false), |
|---|
| 824 | m_trap_mask(0), |
|---|
| 825 | m_report_mask(-1), |
|---|
| 826 | m_no_repeat_mask(0), |
|---|
| 827 | m_magic_state(MAGIC_NONE) |
|---|
| 828 | { |
|---|
| 829 | struct iss_t::DataRequest init = ISS_DREQ_INITIALIZER; |
|---|
| 830 | m_last_data_access = init; |
|---|
| 831 | |
|---|
| 832 | if ( !s_memory_state ) { |
|---|
| 833 | std::cerr |
|---|
| 834 | << std::endl |
|---|
| 835 | << "You must call the static initialized with:" << std::endl |
|---|
| 836 | << "soclib::common::IssMemchecker<...>::init( mapping_table, loader );" << std::endl |
|---|
| 837 | << "Prior to any IssMemchecker constructor." << std::endl |
|---|
| 838 | << std::endl; |
|---|
| 839 | abort(); |
|---|
| 840 | } |
|---|
| 841 | |
|---|
| 842 | m_comm_address = s_memory_state->comm_address(); |
|---|
| 843 | m_fp_reg_id = iss_t::s_fp_register_no; |
|---|
| 844 | m_sp_reg_id = iss_t::s_sp_register_no; |
|---|
| 845 | |
|---|
| 846 | m_current_context = s_memory_state->unknown_context; |
|---|
| 847 | m_last_context = s_memory_state->unknown_context; |
|---|
| 848 | m_current_context->ref(); |
|---|
| 849 | m_last_context->ref(); |
|---|
| 850 | |
|---|
| 851 | if ( const char *env = getenv( "SOCLIB_MEMCHK" ) ) { |
|---|
| 852 | m_opt_dump_iss = strchr( env, 'I' ); |
|---|
| 853 | m_opt_dump_access = strchr( env, 'A' ); |
|---|
| 854 | m_opt_show_enable = strchr( env, 'E' ); |
|---|
| 855 | m_opt_show_ctx = strchr( env, 'C' ); |
|---|
| 856 | m_opt_show_ctxsw = strchr( env, 'S' ); |
|---|
| 857 | m_opt_show_region = strchr( env, 'R' ); |
|---|
| 858 | m_trap_mask = strchr( env, 'T' ) ? -1 : 0; |
|---|
| 859 | m_opt_show_lockops = strchr( env, 'L' ); |
|---|
| 860 | m_opt_exit_on_error = strchr( env, 'X' ); |
|---|
| 861 | } |
|---|
| 862 | |
|---|
| 863 | if ( ident == 0 ) |
|---|
| 864 | std::cerr << "[MemChecker] SOCLIB_MEMCHK env variable may contain the following flag letters: " << std::endl |
|---|
| 865 | << " R (show region changes), C (show context ops), S (show context switch), " << std::endl |
|---|
| 866 | << " T (raise gdb except on err), I (show iss dump), A (show access details), " << std::endl |
|---|
| 867 | << " L (show locks accesses), E (show checks enable X (exit simulation on err)" << std::endl |
|---|
| 868 | << " => See http://www.soclib.fr/trac/dev/wiki/Tools/MemoryChecker" << std::endl; |
|---|
| 869 | |
|---|
| 870 | if ( const char *env = getenv( "SOCLIB_MEMCHK_TRAPON" ) ) { |
|---|
| 871 | m_trap_mask = strtoul(env, NULL, 0); |
|---|
| 872 | } |
|---|
| 873 | |
|---|
| 874 | if ( const char *env = getenv( "SOCLIB_MEMCHK_REPORT" ) ) { |
|---|
| 875 | m_report_mask = strtoul(env, NULL, 0); |
|---|
| 876 | } |
|---|
| 877 | } |
|---|
| 878 | |
|---|
| 879 | template<typename iss_t> |
|---|
| 880 | uint32_t IssMemchecker<iss_t>::register_get(uint32_t reg_no) const |
|---|
| 881 | { |
|---|
| 882 | assert( reg_no < ISS_MEMCHECKER_REGISTER_MAX && "Undefined regsiter" ); |
|---|
| 883 | |
|---|
| 884 | switch ((enum SoclibIssMemcheckerRegisters)reg_no) { |
|---|
| 885 | case ISS_MEMCHECKER_CONTEXT_SWITCH: |
|---|
| 886 | return m_current_context->id(); |
|---|
| 887 | case ISS_MEMCHECKER_R1: |
|---|
| 888 | return m_current_context->m_stack_lower; |
|---|
| 889 | case ISS_MEMCHECKER_R2: |
|---|
| 890 | return m_current_context->m_stack_upper; |
|---|
| 891 | default: |
|---|
| 892 | assert(!"This register is write only"); |
|---|
| 893 | return 0; |
|---|
| 894 | } |
|---|
| 895 | } |
|---|
| 896 | |
|---|
| 897 | #define ISS_MEMCHECKER_MAGIC_VAL_SWAPPED \ |
|---|
| 898 | (((ISS_MEMCHECKER_MAGIC_VAL << 24) & 0xff000000) | \ |
|---|
| 899 | ((ISS_MEMCHECKER_MAGIC_VAL << 8) & 0x00ff0000) | \ |
|---|
| 900 | ((ISS_MEMCHECKER_MAGIC_VAL >> 8) & 0x0000ff00) | \ |
|---|
| 901 | ((ISS_MEMCHECKER_MAGIC_VAL >> 24) & 0x000000ff)) |
|---|
| 902 | |
|---|
| 903 | template<typename iss_t> |
|---|
| 904 | void IssMemchecker<iss_t>::register_set(uint32_t reg_no, uint32_t value) |
|---|
| 905 | { |
|---|
| 906 | assert( reg_no < ISS_MEMCHECKER_REGISTER_MAX && "Undefined regsiter" ); |
|---|
| 907 | |
|---|
| 908 | #if defined(SOCLIB_MODULE_DEBUG) |
|---|
| 909 | std::cout |
|---|
| 910 | << "memchecker register set " << std::dec << reg_no |
|---|
| 911 | << " val: " << std::hex << value |
|---|
| 912 | << std::endl; |
|---|
| 913 | #endif |
|---|
| 914 | |
|---|
| 915 | enum SoclibIssMemcheckerRegisters reg_id = (enum SoclibIssMemcheckerRegisters)reg_no; |
|---|
| 916 | |
|---|
| 917 | #if 1 // Irq get enabled before last write occurs, need a write barrier in software |
|---|
| 918 | if ( (m_enabled_checks & ISS_MEMCHECKER_CHECK_IRQ) && |
|---|
| 919 | iss_t::debugGetRegisterValue(iss_t::ISS_DEBUG_REG_IS_INTERRUPTIBLE) ) { |
|---|
| 920 | report_error( ERROR_IRQ_ENABLED_MAGIC ); |
|---|
| 921 | } |
|---|
| 922 | #endif |
|---|
| 923 | |
|---|
| 924 | if (reg_id != ISS_MEMCHECKER_MAGIC && m_magic_state == MAGIC_NONE) |
|---|
| 925 | return; |
|---|
| 926 | |
|---|
| 927 | switch (reg_id) { |
|---|
| 928 | case ISS_MEMCHECKER_MAGIC: |
|---|
| 929 | switch (m_magic_state) { |
|---|
| 930 | case MAGIC_NONE: |
|---|
| 931 | switch (value) { |
|---|
| 932 | case ISS_MEMCHECKER_MAGIC_VAL: |
|---|
| 933 | m_magic_state = MAGIC_LE; |
|---|
| 934 | break; |
|---|
| 935 | case ISS_MEMCHECKER_MAGIC_VAL_SWAPPED: |
|---|
| 936 | m_magic_state = MAGIC_BE; |
|---|
| 937 | break; |
|---|
| 938 | default: |
|---|
| 939 | report_error(ERROR_BAD_MAGIC_OP, value); |
|---|
| 940 | return; |
|---|
| 941 | } |
|---|
| 942 | break; |
|---|
| 943 | case MAGIC_DELAYED: |
|---|
| 944 | // Cant access memchecker when in delayed magic |
|---|
| 945 | report_error(ERROR_BAD_MAGIC_OP, value); |
|---|
| 946 | break; |
|---|
| 947 | default: |
|---|
| 948 | if (value != 0) |
|---|
| 949 | report_error(ERROR_BAD_MAGIC_OP, value); |
|---|
| 950 | m_magic_state = MAGIC_NONE; |
|---|
| 951 | break; |
|---|
| 952 | } |
|---|
| 953 | break; |
|---|
| 954 | case ISS_MEMCHECKER_R1: |
|---|
| 955 | m_r1 = value; |
|---|
| 956 | break; |
|---|
| 957 | case ISS_MEMCHECKER_R2: |
|---|
| 958 | m_r2 = value; |
|---|
| 959 | break; |
|---|
| 960 | |
|---|
| 961 | case ISS_MEMCHECKER_CONTEXT_ID_CREATE_TMP: |
|---|
| 962 | case ISS_MEMCHECKER_CONTEXT_ID_CREATE: |
|---|
| 963 | { |
|---|
| 964 | if ( m_opt_show_ctx ) { |
|---|
| 965 | std::cout << " -----------------" |
|---|
| 966 | << MEMCHK_COLOR_INFOC(" New execution context #" << std::hex << value) |
|---|
| 967 | << " by " << iss_t::m_name << " cpu" << std::endl << std::endl; |
|---|
| 968 | report_current_ctx(); |
|---|
| 969 | std::cout << " New stack " << std::hex << m_r1 << "-" << (uint64_t)m_r1+m_r2 |
|---|
| 970 | << std::dec << " (" << m_r2 << " bytes)" << std::endl << std::endl; |
|---|
| 971 | } |
|---|
| 972 | |
|---|
| 973 | if ( ! s_memory_state->context_create( |
|---|
| 974 | value, |
|---|
| 975 | new ContextState( value, m_r1, (uint64_t)m_r1+m_r2, |
|---|
| 976 | reg_id == ISS_MEMCHECKER_CONTEXT_ID_CREATE_TMP ) ) ) |
|---|
| 977 | report_error(ERROR_BAD_CONTEXT_CREATE, value); |
|---|
| 978 | |
|---|
| 979 | bool err = false; |
|---|
| 980 | |
|---|
| 981 | for ( uint64_t addr = m_r1; addr < (uint64_t)m_r1+m_r2; addr+= 4 ) { |
|---|
| 982 | AddressInfo *ai = s_memory_state->info_for_address(addr); |
|---|
| 983 | if ( ! ( ai->region()->state() & ( |
|---|
| 984 | __iss_memchecker::RegionInfo::REGION_STATE_ALLOCATED |
|---|
| 985 | | __iss_memchecker::RegionInfo::REGION_STATE_GLOBAL |
|---|
| 986 | | __iss_memchecker::RegionInfo::REGION_STATE_STACK |
|---|
| 987 | ) ) ) { |
|---|
| 988 | err = true; |
|---|
| 989 | m_last_region_touched = ai->region(); |
|---|
| 990 | } |
|---|
| 991 | ai->set_initialized(false); |
|---|
| 992 | } |
|---|
| 993 | |
|---|
| 994 | if ( (m_enabled_checks & ISS_MEMCHECKER_CHECK_REGION) && err) |
|---|
| 995 | report_error(ERROR_CREATING_STACK_NOT_ALLOC); |
|---|
| 996 | break; |
|---|
| 997 | } |
|---|
| 998 | |
|---|
| 999 | case ISS_MEMCHECKER_INITIALIZED: |
|---|
| 1000 | { |
|---|
| 1001 | AddressInfo *ai = s_memory_state->info_for_address( value ); |
|---|
| 1002 | ai->set_initialized(true); |
|---|
| 1003 | break; |
|---|
| 1004 | } |
|---|
| 1005 | |
|---|
| 1006 | case ISS_MEMCHECKER_LOCK_DECLARE: |
|---|
| 1007 | { |
|---|
| 1008 | AddressInfo *ai = s_memory_state->info_for_address( m_r1 ); |
|---|
| 1009 | ai->set_spinlock(value != 0); |
|---|
| 1010 | break; |
|---|
| 1011 | } |
|---|
| 1012 | |
|---|
| 1013 | case ISS_MEMCHECKER_DELAYED_MAGIC: |
|---|
| 1014 | { |
|---|
| 1015 | m_delayed_pc_min = get_cpu_pc(); |
|---|
| 1016 | m_delayed_pc_max = value; |
|---|
| 1017 | m_magic_state = MAGIC_DELAYED; |
|---|
| 1018 | break; |
|---|
| 1019 | } |
|---|
| 1020 | |
|---|
| 1021 | case ISS_MEMCHECKER_BYPASS_SP_CHECK: |
|---|
| 1022 | { |
|---|
| 1023 | assert( m_r1 <= m_r2 ); |
|---|
| 1024 | if (value) { |
|---|
| 1025 | assert( m_r2 - m_r1 < 8192 ); // ensure we do not declare large areas |
|---|
| 1026 | m_bypass_pc |= address_set_t(m_r1, m_r2); |
|---|
| 1027 | } |
|---|
| 1028 | else |
|---|
| 1029 | m_bypass_pc &= ~address_set_t(m_r1, m_r2); |
|---|
| 1030 | break; |
|---|
| 1031 | } |
|---|
| 1032 | |
|---|
| 1033 | case ISS_MEMCHECKER_CONTEXT_ID_CHANGE: |
|---|
| 1034 | { |
|---|
| 1035 | if ( m_opt_show_ctx ) { |
|---|
| 1036 | std::cout << " -----------------" |
|---|
| 1037 | << MEMCHK_COLOR_INFOC(" Rename context #" << std::hex << m_r1 << " to " << value) |
|---|
| 1038 | << " by " << iss_t::m_name << " cpu" << std::endl << std::endl; |
|---|
| 1039 | report_current_ctx(); |
|---|
| 1040 | } |
|---|
| 1041 | |
|---|
| 1042 | ContextState *ref = s_memory_state->context_get( m_r1 ); |
|---|
| 1043 | ContextState *n = new ContextState( |
|---|
| 1044 | value, ref->m_stack_lower, ref->m_stack_upper ); |
|---|
| 1045 | |
|---|
| 1046 | if ( ! s_memory_state->context_delete(m_r1) ) |
|---|
| 1047 | report_error(ERROR_BAD_CONTEXT_DEL, m_r1); |
|---|
| 1048 | |
|---|
| 1049 | if ( ! s_memory_state->context_create( value, n ) ) |
|---|
| 1050 | report_error(ERROR_BAD_CONTEXT_CREATE, value); |
|---|
| 1051 | |
|---|
| 1052 | if ( m_current_context->is( m_r1 ) ) { |
|---|
| 1053 | update_context(n); |
|---|
| 1054 | } |
|---|
| 1055 | |
|---|
| 1056 | break; |
|---|
| 1057 | } |
|---|
| 1058 | |
|---|
| 1059 | case ISS_MEMCHECKER_CONTEXT_INVALIDATE: |
|---|
| 1060 | |
|---|
| 1061 | if (value == ISS_MEMCHECKER_ID_CURRENT) |
|---|
| 1062 | value = m_current_context->id(); |
|---|
| 1063 | |
|---|
| 1064 | if ( m_opt_show_ctx ) { |
|---|
| 1065 | std::cout << " -----------------" |
|---|
| 1066 | << MEMCHK_COLOR_INFOC(" Invalidate context #" << std::hex << value) |
|---|
| 1067 | << " by " << iss_t::m_name << " cpu" << std::endl << std::endl; |
|---|
| 1068 | report_current_ctx(); |
|---|
| 1069 | std::cout << std::endl; |
|---|
| 1070 | } |
|---|
| 1071 | |
|---|
| 1072 | if ( !s_memory_state->context_invalidate( value ) ) { |
|---|
| 1073 | report_error(ERROR_BAD_CONTEXT_INVALIDATE, value); |
|---|
| 1074 | } |
|---|
| 1075 | |
|---|
| 1076 | break; |
|---|
| 1077 | |
|---|
| 1078 | case ISS_MEMCHECKER_CONTEXT_ID_DELETE: |
|---|
| 1079 | |
|---|
| 1080 | if (value == ISS_MEMCHECKER_ID_CURRENT) |
|---|
| 1081 | value = m_current_context->id(); |
|---|
| 1082 | |
|---|
| 1083 | if ( m_opt_show_ctx ) { |
|---|
| 1084 | std::cout << " -----------------" |
|---|
| 1085 | << MEMCHK_COLOR_INFOC(" Delete context #" << std::hex << value) |
|---|
| 1086 | << " by " << iss_t::m_name << " cpu" << std::endl << std::endl; |
|---|
| 1087 | report_current_ctx(); |
|---|
| 1088 | std::cout << std::endl; |
|---|
| 1089 | } |
|---|
| 1090 | |
|---|
| 1091 | if ( m_current_context->is( value ) ) { |
|---|
| 1092 | update_context(s_memory_state->unknown_context); |
|---|
| 1093 | } |
|---|
| 1094 | |
|---|
| 1095 | if ( !s_memory_state->context_delete(value) ) |
|---|
| 1096 | report_error(ERROR_BAD_CONTEXT_DEL, value); |
|---|
| 1097 | |
|---|
| 1098 | break; |
|---|
| 1099 | |
|---|
| 1100 | case ISS_MEMCHECKER_CONTEXT_SWITCH: |
|---|
| 1101 | { |
|---|
| 1102 | m_no_repeat_mask &= ~ERROR_IRQ_ENABLED_TMP; |
|---|
| 1103 | |
|---|
| 1104 | if ( m_opt_show_ctxsw ) { |
|---|
| 1105 | std::cout << " -----------------" |
|---|
| 1106 | << MEMCHK_COLOR_INFOS(" Context switch to #" << std::hex << value) |
|---|
| 1107 | << " by " << iss_t::m_name << " cpu" << std::endl << std::endl; |
|---|
| 1108 | report_current_ctx(); |
|---|
| 1109 | std::cout << std::endl; |
|---|
| 1110 | } |
|---|
| 1111 | |
|---|
| 1112 | if ( m_current_context->temporary() ) { |
|---|
| 1113 | uint32_t tid = m_current_context->id(); |
|---|
| 1114 | s_memory_state->context_delete( tid ); |
|---|
| 1115 | |
|---|
| 1116 | if ( m_opt_show_ctxsw ) |
|---|
| 1117 | std::cout << " Deleted temporary context #" |
|---|
| 1118 | << std::hex << tid << std::endl << std::endl; |
|---|
| 1119 | } |
|---|
| 1120 | |
|---|
| 1121 | ContextState *cs = s_memory_state->context_get( value ); |
|---|
| 1122 | update_context( cs ); |
|---|
| 1123 | |
|---|
| 1124 | if ( cs == s_memory_state->unknown_context || !cs->valid() ) |
|---|
| 1125 | report_error(ERROR_BAD_CONTEXT_SWITCH, value); |
|---|
| 1126 | |
|---|
| 1127 | break; |
|---|
| 1128 | } |
|---|
| 1129 | |
|---|
| 1130 | case ISS_MEMCHECKER_MEMORY_REGION_UPDATE: |
|---|
| 1131 | { |
|---|
| 1132 | __iss_memchecker::RegionInfo::State state; |
|---|
| 1133 | switch (value) { |
|---|
| 1134 | case ISS_MEMCHECKER_REGION_FREE: |
|---|
| 1135 | state = __iss_memchecker::RegionInfo::REGION_STATE_FREE; |
|---|
| 1136 | break; |
|---|
| 1137 | case ISS_MEMCHECKER_REGION_ALLOC: |
|---|
| 1138 | state = __iss_memchecker::RegionInfo::REGION_STATE_ALLOCATED; |
|---|
| 1139 | break; |
|---|
| 1140 | case ISS_MEMCHECKER_REGION_NONALLOC_STACK: |
|---|
| 1141 | state = __iss_memchecker::RegionInfo::REGION_STATE_STACK; |
|---|
| 1142 | break; |
|---|
| 1143 | case ISS_MEMCHECKER_REGION_GLOBAL: |
|---|
| 1144 | state = __iss_memchecker::RegionInfo::REGION_STATE_GLOBAL; |
|---|
| 1145 | break; |
|---|
| 1146 | default: |
|---|
| 1147 | assert(!"Invalid region state"); |
|---|
| 1148 | } |
|---|
| 1149 | |
|---|
| 1150 | if ( m_opt_show_region ) { |
|---|
| 1151 | std::cout << " -----------------" |
|---|
| 1152 | << MEMCHK_COLOR_INFOR(" Region " << std::hex << m_r1 << "-" << (uint64_t)m_r1+m_r2 |
|---|
| 1153 | << " now " << RegionInfo::state_str(state)) |
|---|
| 1154 | << " by " << iss_t::m_name << " cpu" << std::endl << std::endl; |
|---|
| 1155 | report_current_ctx(); |
|---|
| 1156 | std::cout << std::endl; |
|---|
| 1157 | } |
|---|
| 1158 | |
|---|
| 1159 | uint32_t lta; |
|---|
| 1160 | error_level_t e = s_memory_state->region_update_state( |
|---|
| 1161 | state, get_cpu_pc(), m_r1, m_r2, &m_last_region_touched, <a ); |
|---|
| 1162 | |
|---|
| 1163 | report_error( e, lta ); |
|---|
| 1164 | break; |
|---|
| 1165 | } |
|---|
| 1166 | case ISS_MEMCHECKER_ENABLE_CHECKS: |
|---|
| 1167 | |
|---|
| 1168 | m_enabled_checks |= value; |
|---|
| 1169 | |
|---|
| 1170 | if ( m_opt_show_enable ) { |
|---|
| 1171 | std::cout << " -----------------" |
|---|
| 1172 | << MEMCHK_COLOR_INFOR(" Enabled checks " << std::hex << value |
|---|
| 1173 | << " (new value is " << m_enabled_checks << ")" ) |
|---|
| 1174 | << " by " << iss_t::m_name << " cpu" << std::endl << std::endl; |
|---|
| 1175 | report_current_ctx(); |
|---|
| 1176 | std::cout << std::endl; |
|---|
| 1177 | } |
|---|
| 1178 | |
|---|
| 1179 | break; |
|---|
| 1180 | case ISS_MEMCHECKER_DISABLE_CHECKS: |
|---|
| 1181 | |
|---|
| 1182 | m_enabled_checks &= ~value; |
|---|
| 1183 | |
|---|
| 1184 | if ( m_opt_show_enable ) { |
|---|
| 1185 | std::cout << " -----------------" |
|---|
| 1186 | << MEMCHK_COLOR_INFOR(" Disabled checks " << std::hex << value |
|---|
| 1187 | << " (new value is " << m_enabled_checks << ")" ) |
|---|
| 1188 | << " by " << iss_t::m_name << " cpu" << std::endl << std::endl; |
|---|
| 1189 | report_current_ctx(); |
|---|
| 1190 | std::cout << std::endl; |
|---|
| 1191 | } |
|---|
| 1192 | |
|---|
| 1193 | break; |
|---|
| 1194 | |
|---|
| 1195 | case ISS_MEMCHECKER_SET_SP_REG: |
|---|
| 1196 | m_sp_reg_id = value; |
|---|
| 1197 | break; |
|---|
| 1198 | case ISS_MEMCHECKER_SET_FP_REG: |
|---|
| 1199 | m_fp_reg_id = value; |
|---|
| 1200 | break; |
|---|
| 1201 | |
|---|
| 1202 | default: |
|---|
| 1203 | assert(!"Unknown register"); |
|---|
| 1204 | break; |
|---|
| 1205 | } |
|---|
| 1206 | } |
|---|
| 1207 | |
|---|
| 1208 | template<typename iss_t> |
|---|
| 1209 | void IssMemchecker<iss_t>::update_context( ContextState *state ) |
|---|
| 1210 | { |
|---|
| 1211 | #if defined(SOCLIB_MODULE_DEBUG) |
|---|
| 1212 | std::cout << iss_t::m_name |
|---|
| 1213 | << " switching from " << *m_current_context |
|---|
| 1214 | << " to " << *state << std::endl; |
|---|
| 1215 | #endif |
|---|
| 1216 | |
|---|
| 1217 | #if 1 |
|---|
| 1218 | m_last_context->unref(); |
|---|
| 1219 | m_last_context = m_current_context; |
|---|
| 1220 | #else |
|---|
| 1221 | m_current_context->unref(); |
|---|
| 1222 | #endif |
|---|
| 1223 | |
|---|
| 1224 | m_current_context->unschedule(); |
|---|
| 1225 | m_current_context = state; |
|---|
| 1226 | m_current_context->schedule(m_cpuid); |
|---|
| 1227 | m_current_context->ref(); |
|---|
| 1228 | } |
|---|
| 1229 | |
|---|
| 1230 | template<typename iss_t> |
|---|
| 1231 | void IssMemchecker<iss_t>::handle_comm( const struct iss_t::DataRequest &dreq ) |
|---|
| 1232 | { |
|---|
| 1233 | uint32_t reg_no = (dreq.addr-m_comm_address)/4; |
|---|
| 1234 | assert( dreq.be == 0xf && "Only read/write word are allowed in memchecker area" ); |
|---|
| 1235 | |
|---|
| 1236 | switch ( dreq.type ) { |
|---|
| 1237 | case iss_t::DATA_READ: |
|---|
| 1238 | m_data_answer_value = register_get(reg_no); |
|---|
| 1239 | if ( m_magic_state == MAGIC_BE ) |
|---|
| 1240 | m_data_answer_value = soclib::endian::uint32_swap(m_data_answer_value); |
|---|
| 1241 | break; |
|---|
| 1242 | case iss_t::DATA_WRITE: { |
|---|
| 1243 | uint32_t data = dreq.wdata; |
|---|
| 1244 | m_data_answer_value = 0; |
|---|
| 1245 | if ( m_magic_state == MAGIC_BE ) |
|---|
| 1246 | data = soclib::endian::uint32_swap(data); |
|---|
| 1247 | register_set(reg_no, data); |
|---|
| 1248 | break; |
|---|
| 1249 | } |
|---|
| 1250 | case iss_t::XTN_WRITE: |
|---|
| 1251 | case iss_t::XTN_READ: |
|---|
| 1252 | case iss_t::DATA_LL: |
|---|
| 1253 | case iss_t::DATA_SC: |
|---|
| 1254 | assert(!"Only read & write allowed in memchecker area"); |
|---|
| 1255 | break; |
|---|
| 1256 | } |
|---|
| 1257 | m_has_data_answer = true; |
|---|
| 1258 | } |
|---|
| 1259 | |
|---|
| 1260 | template<typename iss_t> |
|---|
| 1261 | void IssMemchecker<iss_t>::check_data_access( const struct iss_t::DataRequest &dreq, |
|---|
| 1262 | const struct iss_t::DataResponse &drsp ) |
|---|
| 1263 | { |
|---|
| 1264 | error_level_t err = ERROR_NONE; |
|---|
| 1265 | AddressInfo *ai = s_memory_state->info_for_address(dreq.addr); |
|---|
| 1266 | const char *op = NULL; |
|---|
| 1267 | |
|---|
| 1268 | if (dreq.addr == 0) |
|---|
| 1269 | err |= ERROR_NULL_POINTER_ACCESS; |
|---|
| 1270 | |
|---|
| 1271 | switch ( dreq.type ) { |
|---|
| 1272 | case iss_t::DATA_LL: |
|---|
| 1273 | if ( ai->is_spinlock() ) { |
|---|
| 1274 | if ( m_held_locks.count(dreq.addr) ) |
|---|
| 1275 | err |= ERROR_LOCK_DEAD_LOCK; |
|---|
| 1276 | |
|---|
| 1277 | if ( m_opt_show_lockops && |
|---|
| 1278 | m_last_data_access == dreq && !(m_blast_data_access == m_last_data_access) ) { |
|---|
| 1279 | op = "Spinning on"; |
|---|
| 1280 | } |
|---|
| 1281 | } |
|---|
| 1282 | case iss_t::DATA_READ: |
|---|
| 1283 | if ( m_enabled_checks & ISS_MEMCHECKER_CHECK_INIT ) |
|---|
| 1284 | err |= ai->do_read(); |
|---|
| 1285 | break; |
|---|
| 1286 | |
|---|
| 1287 | case iss_t::DATA_SC: |
|---|
| 1288 | err |= ai->do_write(); |
|---|
| 1289 | |
|---|
| 1290 | if ( drsp.rdata ) // sc failed |
|---|
| 1291 | break; |
|---|
| 1292 | |
|---|
| 1293 | case iss_t::DATA_WRITE: |
|---|
| 1294 | err |= ai->do_write(); |
|---|
| 1295 | |
|---|
| 1296 | // record held spin-locks states |
|---|
| 1297 | if ( ai->is_spinlock() ) { |
|---|
| 1298 | if ( dreq.type == iss_t::DATA_WRITE || drsp.rdata == Iss2::SC_ATOMIC ) { |
|---|
| 1299 | m_no_repeat_mask &= ~(ERROR_IRQ_ENABLED_LOCK | ERROR_LOCK_DEAD_LOCK); |
|---|
| 1300 | |
|---|
| 1301 | if (dreq.wdata) { |
|---|
| 1302 | m_held_locks[dreq.addr] = true; |
|---|
| 1303 | |
|---|
| 1304 | if ( m_opt_show_lockops ) |
|---|
| 1305 | op = "Lock"; |
|---|
| 1306 | } else { |
|---|
| 1307 | m_held_locks.erase(dreq.addr); |
|---|
| 1308 | if ( m_opt_show_lockops ) |
|---|
| 1309 | op = "Unlock"; |
|---|
| 1310 | } |
|---|
| 1311 | } |
|---|
| 1312 | } |
|---|
| 1313 | |
|---|
| 1314 | break; |
|---|
| 1315 | case iss_t::XTN_WRITE: |
|---|
| 1316 | case iss_t::XTN_READ: |
|---|
| 1317 | return; |
|---|
| 1318 | } |
|---|
| 1319 | |
|---|
| 1320 | if (op) { |
|---|
| 1321 | std::cout << " -----------------" |
|---|
| 1322 | << MEMCHK_COLOR_INFOL(" " << op << " " << std::hex << dreq.addr) |
|---|
| 1323 | << " by " << iss_t::m_name << " cpu" << std::endl << std::endl; |
|---|
| 1324 | report_current_ctx(); |
|---|
| 1325 | std::cout << std::endl; |
|---|
| 1326 | } |
|---|
| 1327 | |
|---|
| 1328 | m_blast_data_access = m_last_data_access; |
|---|
| 1329 | m_last_data_access = dreq; |
|---|
| 1330 | |
|---|
| 1331 | uint32_t sp_bound = get_cpu_sp() - iss_t::debugGetRegisterValue(iss_t::ISS_DEBUG_REG_STACK_REDZONE_SIZE); |
|---|
| 1332 | |
|---|
| 1333 | if ( m_current_context->stack_contains(dreq.addr) ) { |
|---|
| 1334 | if ( ( m_enabled_checks & ISS_MEMCHECKER_CHECK_SP ) |
|---|
| 1335 | && dreq.addr < sp_bound ) { |
|---|
| 1336 | err |= ERROR_DATA_ACCESS_BELOW_SP; |
|---|
| 1337 | } |
|---|
| 1338 | } else { |
|---|
| 1339 | if ( m_enabled_checks & ISS_MEMCHECKER_CHECK_REGION ) { |
|---|
| 1340 | RegionInfo *ri = ai->region(); |
|---|
| 1341 | switch ( dreq.type ) { |
|---|
| 1342 | case iss_t::DATA_READ: |
|---|
| 1343 | case iss_t::DATA_LL: |
|---|
| 1344 | err |= ri->do_read(); |
|---|
| 1345 | break; |
|---|
| 1346 | case iss_t::DATA_SC: |
|---|
| 1347 | case iss_t::DATA_WRITE: |
|---|
| 1348 | err |= ri->do_write(); |
|---|
| 1349 | break; |
|---|
| 1350 | case iss_t::XTN_WRITE: |
|---|
| 1351 | case iss_t::XTN_READ: |
|---|
| 1352 | return; |
|---|
| 1353 | } |
|---|
| 1354 | } |
|---|
| 1355 | } |
|---|
| 1356 | |
|---|
| 1357 | report_error(err, dreq.addr); |
|---|
| 1358 | } |
|---|
| 1359 | |
|---|
| 1360 | template<typename iss_t> |
|---|
| 1361 | void IssMemchecker<iss_t>::report_current_ctx() |
|---|
| 1362 | { |
|---|
| 1363 | std::cout << " Executed from PC=" << s_memory_state->get_symbol(get_cpu_pc()) |
|---|
| 1364 | << ", SP=" << get_cpu_sp() << std::endl; |
|---|
| 1365 | std::cout << " " << *m_current_context << std::endl; |
|---|
| 1366 | } |
|---|
| 1367 | |
|---|
| 1368 | template<typename iss_t> |
|---|
| 1369 | void IssMemchecker<iss_t>::report_error(error_level_t errors_, uint32_t extra) |
|---|
| 1370 | { |
|---|
| 1371 | errors_ &= m_report_mask; |
|---|
| 1372 | errors_ &= ~m_no_repeat_mask; |
|---|
| 1373 | m_no_repeat_mask |= (errors_ & repeat_filter); |
|---|
| 1374 | error_level_t old_errors = errors_; |
|---|
| 1375 | |
|---|
| 1376 | while ( errors_ ) { |
|---|
| 1377 | |
|---|
| 1378 | static const char *acc; |
|---|
| 1379 | |
|---|
| 1380 | switch (m_last_data_access.type) { |
|---|
| 1381 | case iss_t::DATA_READ: |
|---|
| 1382 | acc = "read"; |
|---|
| 1383 | break; |
|---|
| 1384 | case iss_t::DATA_WRITE: |
|---|
| 1385 | acc = "write"; |
|---|
| 1386 | break; |
|---|
| 1387 | case iss_t::DATA_LL: |
|---|
| 1388 | acc = "linked load"; |
|---|
| 1389 | break; |
|---|
| 1390 | case iss_t::DATA_SC: |
|---|
| 1391 | acc = "conditional store"; |
|---|
| 1392 | break; |
|---|
| 1393 | default: |
|---|
| 1394 | acc = "special"; |
|---|
| 1395 | } |
|---|
| 1396 | |
|---|
| 1397 | // process one error at once |
|---|
| 1398 | error_level_t error = errors_ & ~(errors_ - 1); |
|---|
| 1399 | |
|---|
| 1400 | uint32_t sp = get_cpu_sp(); |
|---|
| 1401 | uint32_t fp = get_cpu_fp(); |
|---|
| 1402 | uint32_t oob = 0; |
|---|
| 1403 | bool show_access = false; |
|---|
| 1404 | bool show_locks = false; |
|---|
| 1405 | |
|---|
| 1406 | RegionInfo *ri = 0, *ro = 0; |
|---|
| 1407 | |
|---|
| 1408 | // Signal to GDB |
|---|
| 1409 | |
|---|
| 1410 | std::cout << " -----------------"; |
|---|
| 1411 | |
|---|
| 1412 | AddressInfo *ai = s_memory_state->info_for_address(m_last_data_access.addr); |
|---|
| 1413 | |
|---|
| 1414 | switch ( error ) { |
|---|
| 1415 | |
|---|
| 1416 | case ERROR_UNINITIALIZED_WORD: |
|---|
| 1417 | std::cout << MEMCHK_COLOR_WARN(" Memory " << acc << " in uninitialized word at " |
|---|
| 1418 | << std::hex << m_last_data_access.addr); |
|---|
| 1419 | ri = ai->region(); |
|---|
| 1420 | show_access = true; |
|---|
| 1421 | break; |
|---|
| 1422 | |
|---|
| 1423 | case ERROR_REGION_OVERLAP: |
|---|
| 1424 | std::cout << MEMCHK_COLOR_ERR(" Region overlap "); |
|---|
| 1425 | break; |
|---|
| 1426 | |
|---|
| 1427 | case ERROR_INVALID_ACCESS: |
|---|
| 1428 | ri = ai->region(); |
|---|
| 1429 | std::cout << MEMCHK_COLOR_ERR(" Memory " << acc << |
|---|
| 1430 | " in " << ri->state_str() << " region at " |
|---|
| 1431 | << std::hex << m_last_data_access.addr); |
|---|
| 1432 | show_access = true; |
|---|
| 1433 | break; |
|---|
| 1434 | |
|---|
| 1435 | case ERROR_NULL_POINTER_ACCESS: |
|---|
| 1436 | ri = ai->region(); |
|---|
| 1437 | std::cout << MEMCHK_COLOR_ERR(" Null pointer " << acc << " access" ); |
|---|
| 1438 | break; |
|---|
| 1439 | |
|---|
| 1440 | case ERROR_CREATING_STACK_NOT_ALLOC: |
|---|
| 1441 | std::cout << MEMCHK_COLOR_ERR(" Stack creation in non-allocated memory"); |
|---|
| 1442 | ri = m_last_region_touched; |
|---|
| 1443 | break; |
|---|
| 1444 | |
|---|
| 1445 | case ERROR_BAD_REGION_REALLOCATION: |
|---|
| 1446 | std::cout << MEMCHK_COLOR_ERR(" Bad memory region state change at: " |
|---|
| 1447 | << std::hex << extra); |
|---|
| 1448 | ro = m_last_region_touched; |
|---|
| 1449 | ri = s_memory_state->info_for_address(extra)->region(); |
|---|
| 1450 | break; |
|---|
| 1451 | |
|---|
| 1452 | case ERROR_CONTEXT_ON_TWO_CPUS: |
|---|
| 1453 | std::cout << MEMCHK_COLOR_ERR(" Context running on two processors"); |
|---|
| 1454 | break; |
|---|
| 1455 | |
|---|
| 1456 | case ERROR_SP_OUTOFBOUNDS: |
|---|
| 1457 | std::cout << MEMCHK_COLOR_ERR(" Stack pointer out of bounds: ") << std::hex << sp; |
|---|
| 1458 | oob = sp; |
|---|
| 1459 | break; |
|---|
| 1460 | |
|---|
| 1461 | case ERROR_FP_OUTOFBOUNDS: |
|---|
| 1462 | std::cout << MEMCHK_COLOR_ERR(" Frame pointer out of bounds: ") << std::hex << fp; |
|---|
| 1463 | oob = fp; |
|---|
| 1464 | break; |
|---|
| 1465 | |
|---|
| 1466 | case ERROR_DATA_ACCESS_BELOW_SP: |
|---|
| 1467 | std::cout << MEMCHK_COLOR_WARN(" Data " << acc << " below stack pointer at " |
|---|
| 1468 | << std::hex << m_last_data_access.addr); |
|---|
| 1469 | show_access = true; |
|---|
| 1470 | break; |
|---|
| 1471 | |
|---|
| 1472 | case ERROR_BAD_CONTEXT_DEL: |
|---|
| 1473 | std::cout << MEMCHK_COLOR_ERR(" Trying to delete non-existing context: " |
|---|
| 1474 | << std::hex << extra); |
|---|
| 1475 | show_access = true; |
|---|
| 1476 | break; |
|---|
| 1477 | |
|---|
| 1478 | case ERROR_BAD_CONTEXT_CREATE: |
|---|
| 1479 | std::cout << MEMCHK_COLOR_ERR(" Trying to create context with existing id: " |
|---|
| 1480 | << std::hex << extra); |
|---|
| 1481 | show_access = true; |
|---|
| 1482 | break; |
|---|
| 1483 | |
|---|
| 1484 | case ERROR_BAD_CONTEXT_INVALIDATE: |
|---|
| 1485 | std::cout << MEMCHK_COLOR_ERR(" Trying to invalidate context with non-existing id: " |
|---|
| 1486 | << std::hex << extra); |
|---|
| 1487 | show_access = true; |
|---|
| 1488 | break; |
|---|
| 1489 | |
|---|
| 1490 | case ERROR_BAD_CONTEXT_SWITCH: |
|---|
| 1491 | std::cout << MEMCHK_COLOR_ERR(" Trying to switch to an invalid context " |
|---|
| 1492 | << std::hex << extra); |
|---|
| 1493 | show_access = true; |
|---|
| 1494 | break; |
|---|
| 1495 | |
|---|
| 1496 | case ERROR_IRQ_ENABLED_MAGIC: |
|---|
| 1497 | std::cout << MEMCHK_COLOR_ERR(" Processor IRQs enabled while in memchecker magic mode "); |
|---|
| 1498 | break; |
|---|
| 1499 | |
|---|
| 1500 | case ERROR_IRQ_ENABLED_TMP: |
|---|
| 1501 | std::cout << MEMCHK_COLOR_ERR(" Processor IRQs enabled during temporary context execution "); |
|---|
| 1502 | break; |
|---|
| 1503 | |
|---|
| 1504 | case ERROR_IRQ_ENABLED_LOCK: |
|---|
| 1505 | std::cout << MEMCHK_COLOR_WARN(" Processor IRQs enabled while some spinlocks are held "); |
|---|
| 1506 | show_locks = true; |
|---|
| 1507 | break; |
|---|
| 1508 | |
|---|
| 1509 | case ERROR_IRQ_DISABLED_USER: |
|---|
| 1510 | std::cout << MEMCHK_COLOR_WARN(" Processor IRQs disabled in user mode "); |
|---|
| 1511 | break; |
|---|
| 1512 | |
|---|
| 1513 | case ERROR_LOCK_DEAD_LOCK: |
|---|
| 1514 | std::cout << MEMCHK_COLOR_ERR(" Spinlock dead lock "); |
|---|
| 1515 | show_locks = true; |
|---|
| 1516 | break; |
|---|
| 1517 | |
|---|
| 1518 | case ERROR_BAD_MAGIC_OP: |
|---|
| 1519 | std::cout << MEMCHK_COLOR_ERR(" Bad magic register operation: " << std::hex << extra); |
|---|
| 1520 | break; |
|---|
| 1521 | } |
|---|
| 1522 | |
|---|
| 1523 | std::cout << " by " << iss_t::m_name << " cpu" << std::endl << std::endl; |
|---|
| 1524 | |
|---|
| 1525 | report_current_ctx(); |
|---|
| 1526 | |
|---|
| 1527 | if ( error & (ERROR_FP_OUTOFBOUNDS | ERROR_SP_OUTOFBOUNDS ) ) { |
|---|
| 1528 | if ( oob < m_current_context->m_stack_lower ) |
|---|
| 1529 | std::cout << " Out of bounds " << (m_current_context->m_stack_lower - oob) |
|---|
| 1530 | << " bytes below" << std::endl; |
|---|
| 1531 | else if ( oob > m_current_context->m_stack_upper ) |
|---|
| 1532 | std::cout << " " << (oob - m_current_context->m_stack_upper) |
|---|
| 1533 | << " bytes above" << std::endl; |
|---|
| 1534 | } |
|---|
| 1535 | |
|---|
| 1536 | if ( ri ) { |
|---|
| 1537 | std::cout << " Region Current " << *ri << std::endl; |
|---|
| 1538 | |
|---|
| 1539 | if ( RegionInfo *p = ri->prev_state() ) |
|---|
| 1540 | std::cout << " Previous " << *p << std::endl; |
|---|
| 1541 | } |
|---|
| 1542 | |
|---|
| 1543 | if ( ro ) { |
|---|
| 1544 | std::cout << " Offending Current " << *ri << std::endl; |
|---|
| 1545 | |
|---|
| 1546 | if ( RegionInfo *p = ri->prev_state() ) |
|---|
| 1547 | std::cout << " Previous " << *p << std::endl; |
|---|
| 1548 | } |
|---|
| 1549 | |
|---|
| 1550 | if ( show_access ) { |
|---|
| 1551 | if ( m_opt_dump_access ) |
|---|
| 1552 | std::cout << " Memory access " << m_last_data_access << std::endl; |
|---|
| 1553 | |
|---|
| 1554 | BinaryFileSymbolOffset s = s_memory_state->get_symbol(m_last_data_access.addr); |
|---|
| 1555 | |
|---|
| 1556 | if (s.symbol().name() != "Unknown" ) |
|---|
| 1557 | std::cout << " Memory access to " << s << std::endl; |
|---|
| 1558 | } |
|---|
| 1559 | |
|---|
| 1560 | if ( show_locks ) { |
|---|
| 1561 | std::cout << std::endl; |
|---|
| 1562 | for ( held_locks_map_t::iterator i = m_held_locks.begin(); i != m_held_locks.end(); i++ ) |
|---|
| 1563 | std::cout << " Spin-lock held " << MEMCHK_BOLD(i->first) << std::endl; |
|---|
| 1564 | } |
|---|
| 1565 | |
|---|
| 1566 | std::cout << std::endl; |
|---|
| 1567 | |
|---|
| 1568 | if ( m_opt_dump_iss ) { |
|---|
| 1569 | iss_t::dump(); |
|---|
| 1570 | std::cout << std::endl; |
|---|
| 1571 | } |
|---|
| 1572 | |
|---|
| 1573 | if ( ( m_trap_mask & error ) && m_bypass && debugExceptionBypassed( iss_t::EXCL_TRAP ) ) |
|---|
| 1574 | m_bypass = false; |
|---|
| 1575 | |
|---|
| 1576 | errors_ ^= error; |
|---|
| 1577 | } |
|---|
| 1578 | |
|---|
| 1579 | if (old_errors && m_opt_exit_on_error) |
|---|
| 1580 | abort(); |
|---|
| 1581 | } |
|---|
| 1582 | |
|---|
| 1583 | template<typename iss_t> |
|---|
| 1584 | uint32_t IssMemchecker<iss_t>::executeNCycles( |
|---|
| 1585 | uint32_t ncycle, struct iss_t::InstructionResponse irsp, |
|---|
| 1586 | struct iss_t::DataResponse drsp, uint32_t irq_bit_field ) |
|---|
| 1587 | { |
|---|
| 1588 | struct iss_t::InstructionRequest ireq = ISS_IREQ_INITIALIZER; |
|---|
| 1589 | struct iss_t::DataRequest dreq = ISS_DREQ_INITIALIZER; |
|---|
| 1590 | iss_t::getRequests(ireq, dreq); |
|---|
| 1591 | m_bypass = true; |
|---|
| 1592 | |
|---|
| 1593 | assert( !(drsp.valid && !dreq.valid) ); |
|---|
| 1594 | |
|---|
| 1595 | if ( dreq.valid ) { |
|---|
| 1596 | if ( (dreq.addr & ~(uint32_t)0xff) == m_comm_address ) { |
|---|
| 1597 | if ( m_magic_state != MAGIC_NONE || |
|---|
| 1598 | ( dreq.type == iss_t::DATA_WRITE |
|---|
| 1599 | && ( dreq.wdata == ISS_MEMCHECKER_MAGIC_VAL || |
|---|
| 1600 | dreq.wdata == ISS_MEMCHECKER_MAGIC_VAL_SWAPPED ) ) ) { |
|---|
| 1601 | if ( !ireq.valid || irsp.valid ) |
|---|
| 1602 | handle_comm( dreq ); |
|---|
| 1603 | dreq.valid = false; |
|---|
| 1604 | } |
|---|
| 1605 | } |
|---|
| 1606 | } |
|---|
| 1607 | |
|---|
| 1608 | if ( m_has_data_answer ) { |
|---|
| 1609 | assert( !drsp.valid && "Cache speaking while i'm answering ISS" ); |
|---|
| 1610 | drsp.valid = true; |
|---|
| 1611 | drsp.error = false; |
|---|
| 1612 | drsp.rdata = m_data_answer_value; |
|---|
| 1613 | m_has_data_answer = false; |
|---|
| 1614 | |
|---|
| 1615 | } else { |
|---|
| 1616 | if ( drsp.valid ) { |
|---|
| 1617 | check_data_access( dreq, drsp ); |
|---|
| 1618 | } |
|---|
| 1619 | } |
|---|
| 1620 | |
|---|
| 1621 | { |
|---|
| 1622 | uint32_t sp = get_cpu_sp(); |
|---|
| 1623 | if ( m_last_sp && m_last_sp < sp ) { |
|---|
| 1624 | for ( uint32_t i = m_last_sp; i < sp; ++i ) |
|---|
| 1625 | s_memory_state->info_for_address(i)->set_initialized(false); |
|---|
| 1626 | m_last_sp = sp; |
|---|
| 1627 | } |
|---|
| 1628 | } |
|---|
| 1629 | |
|---|
| 1630 | error_level_t errl = ERROR_NONE; |
|---|
| 1631 | |
|---|
| 1632 | switch ( m_magic_state ) { |
|---|
| 1633 | case MAGIC_NONE: |
|---|
| 1634 | if (iss_t::debugGetRegisterValue(iss_t::ISS_DEBUG_REG_IS_USERMODE)) |
|---|
| 1635 | break; |
|---|
| 1636 | |
|---|
| 1637 | if ( (m_enabled_checks & ISS_MEMCHECKER_CHECK_SP) && |
|---|
| 1638 | ! m_current_context->stack_contains(get_cpu_sp()) && |
|---|
| 1639 | ! m_bypass_pc[get_cpu_pc()] ) |
|---|
| 1640 | errl |= ERROR_SP_OUTOFBOUNDS; |
|---|
| 1641 | else |
|---|
| 1642 | m_no_repeat_mask &= ~ERROR_SP_OUTOFBOUNDS; |
|---|
| 1643 | |
|---|
| 1644 | if ( (m_enabled_checks & ISS_MEMCHECKER_CHECK_FP) && |
|---|
| 1645 | ! m_current_context->stack_contains(get_cpu_fp()) && |
|---|
| 1646 | ! m_bypass_pc[get_cpu_pc()] ) |
|---|
| 1647 | errl |= ERROR_FP_OUTOFBOUNDS; |
|---|
| 1648 | else |
|---|
| 1649 | m_no_repeat_mask &= ~ERROR_FP_OUTOFBOUNDS; |
|---|
| 1650 | break; |
|---|
| 1651 | |
|---|
| 1652 | case MAGIC_DELAYED: |
|---|
| 1653 | if ( get_cpu_pc() < m_delayed_pc_min || |
|---|
| 1654 | get_cpu_pc() >= m_delayed_pc_max ) |
|---|
| 1655 | m_magic_state = MAGIC_NONE; |
|---|
| 1656 | break; |
|---|
| 1657 | |
|---|
| 1658 | default: |
|---|
| 1659 | break; |
|---|
| 1660 | } |
|---|
| 1661 | |
|---|
| 1662 | if (m_enabled_checks & ISS_MEMCHECKER_CHECK_IRQ) { |
|---|
| 1663 | if ( iss_t::debugGetRegisterValue(iss_t::ISS_DEBUG_REG_IS_INTERRUPTIBLE) ) { |
|---|
| 1664 | |
|---|
| 1665 | if ( m_current_context->temporary() ) { |
|---|
| 1666 | errl |= ERROR_IRQ_ENABLED_TMP; |
|---|
| 1667 | } |
|---|
| 1668 | |
|---|
| 1669 | if ( !m_held_locks.empty() ) { |
|---|
| 1670 | errl |= ERROR_IRQ_ENABLED_LOCK; |
|---|
| 1671 | } |
|---|
| 1672 | } else { |
|---|
| 1673 | if (iss_t::debugGetRegisterValue(iss_t::ISS_DEBUG_REG_IS_USERMODE)) |
|---|
| 1674 | errl |= ERROR_IRQ_DISABLED_USER; |
|---|
| 1675 | } |
|---|
| 1676 | } |
|---|
| 1677 | |
|---|
| 1678 | report_error(errl, 0); |
|---|
| 1679 | |
|---|
| 1680 | if ( !m_bypass ) |
|---|
| 1681 | return 0; |
|---|
| 1682 | |
|---|
| 1683 | return iss_t::executeNCycles( ncycle, irsp, drsp, irq_bit_field ); |
|---|
| 1684 | } |
|---|
| 1685 | |
|---|
| 1686 | }} |
|---|
| 1687 | |
|---|
| 1688 | |
|---|
| 1689 | // Local Variables: |
|---|
| 1690 | // tab-width: 4 |
|---|
| 1691 | // c-basic-offset: 4 |
|---|
| 1692 | // c-file-offsets:((innamespace . 0)(inline-open . 0)) |
|---|
| 1693 | // indent-tabs-mode: nil |
|---|
| 1694 | // End: |
|---|
| 1695 | |
|---|
| 1696 | // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=4:softtabstop=4 |
|---|