source: trunk/soclib/soclib/iss/iss_memchecker/src/iss_memchecker.cpp @ 2200

Revision 2189, 51.1 KB checked in by becoulet, 3 weeks ago (diff)

added cpu id register (leon) and compare and swap CASA instruction (v9 & leon) to sparc iss

  • Property svn:eol-style set to native
Line 
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
51namespace soclib { namespace common {
52
53namespace __iss_memchecker {
54
55typedef uint32_t error_level_t;
56
57namespace {
58MemoryState * s_memory_state = NULL;
59}
60
61enum {
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
86static 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
93class 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
102public:
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
215class RegionInfo
216{
217public:
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
230private:
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
238public:
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
393class 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
400public:
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
516class 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
527public:
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
775using namespace __iss_memchecker;
776
777
778template<typename iss_t>
779uint32_t IssMemchecker<iss_t>::get_cpu_sp() const
780{
781    return iss_t::debugGetRegisterValue(m_sp_reg_id);
782}
783
784template<typename iss_t>
785uint32_t IssMemchecker<iss_t>::get_cpu_fp() const
786{
787    return iss_t::debugGetRegisterValue(m_fp_reg_id);
788}
789
790template<typename iss_t>
791uint32_t IssMemchecker<iss_t>::get_cpu_pc() const
792{
793    return iss_t::debugGetRegisterValue(iss_t::s_pc_register_no);
794}
795
796
797template<typename iss_t>
798void 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
806template<typename iss_t>
807IssMemchecker<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
879template<typename iss_t>
880uint32_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
903template<typename iss_t>
904void 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, &lta );
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
1208template<typename iss_t>
1209void 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
1230template<typename iss_t>
1231void 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
1260template<typename iss_t>
1261void 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
1360template<typename iss_t>
1361void 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
1368template<typename iss_t>
1369void 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
1583template<typename iss_t>
1584uint32_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
Note: See TracBrowser for help on using the repository browser.