ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sigsegv.cpp
(Generate patch)

Comparing BasiliskII/src/Unix/sigsegv.cpp (file contents):
Revision 1.21 by gbeauche, 2002-10-03T15:49:14Z vs.
Revision 1.22 by gbeauche, 2003-05-14T06:50:05Z

# Line 29 | Line 29
29   #include "config.h"
30   #endif
31  
32 + #include <list>
33   #include <signal.h>
34   #include "sigsegv.h"
35  
36 + #ifndef NO_STD_NAMESPACE
37 + using std::list;
38 + #endif
39 +
40   // Return value type of a signal handler (standard type if not defined)
41   #ifndef RETSIGTYPE
42   #define RETSIGTYPE void
# Line 40 | Line 45
45   // Type of the system signal handler
46   typedef RETSIGTYPE (*signal_handler)(int);
47  
48 < // Is the fault to be ignored?
49 < static bool sigsegv_ignore_fault = false;
48 > // Ignore range chain
49 > struct ignore_range_t {
50 >        sigsegv_address_t       start;
51 >        unsigned long           length;
52 >        int                                     transfer_type;
53 > };
54 >
55 > typedef list<ignore_range_t> ignore_range_list_t;
56 > ignore_range_list_t sigsegv_ignore_ranges;
57  
58   // User's SIGSEGV handler
59   static sigsegv_fault_handler_t sigsegv_fault_handler = 0;
# Line 52 | Line 64 | static sigsegv_state_dumper_t sigsegv_st
64   // Actual SIGSEGV handler installer
65   static bool sigsegv_do_install_handler(int sig);
66  
67 + // Find ignore range matching address
68 + static inline ignore_range_list_t::iterator sigsegv_find_ignore_range(sigsegv_address_t address)
69 + {
70 +        ignore_range_list_t::iterator it;
71 +        for (it = sigsegv_ignore_ranges.begin(); it != sigsegv_ignore_ranges.end(); it++)
72 +                if (address >= it->start && address < it->start + it->length)
73 +                        break;
74 +        return it;
75 + }
76 +
77  
78   /*
79   *  Instruction decoding aids
80   */
81  
60 // Transfer type
61 enum transfer_type_t {
62        TYPE_UNKNOWN,
63        TYPE_LOAD,
64        TYPE_STORE
65 };
66
82   // Transfer size
83   enum transfer_size_t {
84          SIZE_UNKNOWN,
# Line 83 | Line 98 | enum addressing_mode_t {
98   };
99  
100   // Decoded instruction
101 + typedef sigsegv_transfer_type_t transfer_type_t;
102   struct instruction_t {
103          transfer_type_t         transfer_type;
104          transfer_size_t         transfer_size;
# Line 103 | Line 119 | static void powerpc_decode_instruction(i
119          signed int imm = (signed short)(opcode & 0xffff);
120          
121          // Analyze opcode
122 <        transfer_type_t transfer_type = TYPE_UNKNOWN;
122 >        transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
123          transfer_size_t transfer_size = SIZE_UNKNOWN;
124          addressing_mode_t addr_mode = MODE_UNKNOWN;
125          switch (primop) {
126          case 31:
127                  switch (exop) {
128                  case 23:        // lwzx
129 <                        transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
129 >                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
130                  case 55:        // lwzux
131 <                        transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
131 >                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
132                  case 87:        // lbzx
133 <                        transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
133 >                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
134                  case 119:       // lbzux
135 <                        transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
135 >                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
136                  case 151:       // stwx
137 <                        transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
137 >                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_X; break;
138                  case 183:       // stwux
139 <                        transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
139 >                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_UX; break;
140                  case 215:       // stbx
141 <                        transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
141 >                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_X; break;
142                  case 247:       // stbux
143 <                        transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
143 >                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_UX; break;
144                  case 279:       // lhzx
145 <                        transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
145 >                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
146                  case 311:       // lhzux
147 <                        transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
147 >                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
148                  case 343:       // lhax
149 <                        transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
149 >                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
150                  case 375:       // lhaux
151 <                        transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
151 >                        transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
152                  case 407:       // sthx
153 <                        transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
153 >                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_X; break;
154                  case 439:       // sthux
155 <                        transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
155 >                        transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_UX; break;
156                  }
157                  break;
158          
159          case 32:        // lwz
160 <                transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
160 >                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
161          case 33:        // lwzu
162 <                transfer_type = TYPE_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
162 >                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
163          case 34:        // lbz
164 <                transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
164 >                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
165          case 35:        // lbzu
166 <                transfer_type = TYPE_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
166 >                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
167          case 36:        // stw
168 <                transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
168 >                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_NORM; break;
169          case 37:        // stwu
170 <                transfer_type = TYPE_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
170 >                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_LONG; addr_mode = MODE_U; break;
171          case 38:        // stb
172 <                transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
172 >                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_NORM; break;
173          case 39:        // stbu
174 <                transfer_type = TYPE_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
174 >                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_BYTE; addr_mode = MODE_U; break;
175          case 40:        // lhz
176 <                transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
176 >                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
177          case 41:        // lhzu
178 <                transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
178 >                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
179          case 42:        // lha
180 <                transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
180 >                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
181          case 43:        // lhau
182 <                transfer_type = TYPE_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
182 >                transfer_type = SIGSEGV_TRANSFER_LOAD; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
183          case 44:        // sth
184 <                transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
184 >                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_NORM; break;
185          case 45:        // sthu
186 <                transfer_type = TYPE_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
186 >                transfer_type = SIGSEGV_TRANSFER_STORE; transfer_size = SIZE_WORD; addr_mode = MODE_U; break;
187          }
188          
189          // Calculate effective address
# Line 455 | Line 471 | static bool ix86_skip_instruction(unsign
471          if (eip == 0)
472                  return false;
473          
474 <        transfer_type_t transfer_type = TYPE_UNKNOWN;
474 >        transfer_type_t transfer_type = SIGSEGV_TRANSFER_UNKNOWN;
475          transfer_size_t transfer_size = SIZE_LONG;
476          
477          int reg = -1;
# Line 477 | Line 493 | static bool ix86_skip_instruction(unsign
493                  switch (eip[2] & 0xc0) {
494                  case 0x80:
495                      reg = (eip[2] >> 3) & 7;
496 <                    transfer_type = TYPE_LOAD;
496 >                    transfer_type = SIGSEGV_TRANSFER_LOAD;
497                      break;
498                  case 0x40:
499                      reg = (eip[2] >> 3) & 7;
500 <                    transfer_type = TYPE_LOAD;
500 >                    transfer_type = SIGSEGV_TRANSFER_LOAD;
501                      break;
502                  case 0x00:
503                      reg = (eip[2] >> 3) & 7;
504 <                    transfer_type = TYPE_LOAD;
504 >                    transfer_type = SIGSEGV_TRANSFER_LOAD;
505                      break;
506                  }
507                  len += 3 + ix86_step_over_modrm(eip + 2);
# Line 498 | Line 514 | static bool ix86_skip_instruction(unsign
514                  switch (eip[1] & 0xc0) {
515                  case 0x80:
516                          reg = (eip[1] >> 3) & 7;
517 <                        transfer_type = TYPE_LOAD;
517 >                        transfer_type = SIGSEGV_TRANSFER_LOAD;
518                          break;
519                  case 0x40:
520                          reg = (eip[1] >> 3) & 7;
521 <                        transfer_type = TYPE_LOAD;
521 >                        transfer_type = SIGSEGV_TRANSFER_LOAD;
522                          break;
523                  case 0x00:
524                          reg = (eip[1] >> 3) & 7;
525 <                        transfer_type = TYPE_LOAD;
525 >                        transfer_type = SIGSEGV_TRANSFER_LOAD;
526                          break;
527                  }
528                  len += 2 + ix86_step_over_modrm(eip + 1);
# Line 517 | Line 533 | static bool ix86_skip_instruction(unsign
533                  switch (eip[1] & 0xc0) {
534                  case 0x80:
535                          reg = (eip[1] >> 3) & 7;
536 <                        transfer_type = TYPE_STORE;
536 >                        transfer_type = SIGSEGV_TRANSFER_STORE;
537                          break;
538                  case 0x40:
539                          reg = (eip[1] >> 3) & 7;
540 <                        transfer_type = TYPE_STORE;
540 >                        transfer_type = SIGSEGV_TRANSFER_STORE;
541                          break;
542                  case 0x00:
543                          reg = (eip[1] >> 3) & 7;
544 <                        transfer_type = TYPE_STORE;
544 >                        transfer_type = SIGSEGV_TRANSFER_STORE;
545                          break;
546                  }
547                  len += 2 + ix86_step_over_modrm(eip + 1);
548                  break;
549          }
550  
551 <        if (transfer_type == TYPE_UNKNOWN) {
551 >        if (transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
552                  // Unknown machine code, let it crash. Then patch the decoder
553                  return false;
554          }
555  
556 <        if (transfer_type == TYPE_LOAD && reg != -1) {
556 >        if (transfer_type == SIGSEGV_TRANSFER_LOAD && reg != -1) {
557                  static const int x86_reg_map[8] = {
558                          X86_REG_EAX, X86_REG_ECX, X86_REG_EDX, X86_REG_EBX,
559                          X86_REG_ESP, X86_REG_EBP, X86_REG_ESI, X86_REG_EDI
# Line 563 | Line 579 | static bool ix86_skip_instruction(unsign
579   #if DEBUG
580          printf("%08x: %s %s access", regs[X86_REG_EIP],
581                     transfer_size == SIZE_BYTE ? "byte" : transfer_size == SIZE_WORD ? "word" : "long",
582 <                   transfer_type == TYPE_LOAD ? "read" : "write");
582 >                   transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
583          
584          if (reg != -1) {
585                  static const char * x86_reg_str_map[8] = {
586                          "eax", "ecx", "edx", "ebx",
587                          "esp", "ebp", "esi", "edi"
588                  };
589 <                printf(" %s register %%%s", transfer_type == TYPE_LOAD ? "to" : "from", x86_reg_str_map[reg]);
589 >                printf(" %s register %%%s", transfer_type == SIGSEGV_TRANSFER_LOAD ? "to" : "from", x86_reg_str_map[reg]);
590          }
591          printf(", %d bytes instruction\n", len);
592   #endif
# Line 587 | Line 603 | static bool powerpc_skip_instruction(uns
603          instruction_t instr;
604          powerpc_decode_instruction(&instr, *nip_p, regs);
605          
606 <        if (instr.transfer_type == TYPE_UNKNOWN) {
606 >        if (instr.transfer_type == SIGSEGV_TRANSFER_UNKNOWN) {
607                  // Unknown machine code, let it crash. Then patch the decoder
608                  return false;
609          }
610  
611 +        ignore_range_list_t::iterator it = sigsegv_find_ignore_range((sigsegv_address_t)instr.addr);
612 +        if (it == sigsegv_ignore_ranges.end() || ((it->transfer_type & instr.transfer_type) != instr.transfer_type)) {
613 +                // Address doesn't fall into ignore ranges list, let it crash.
614 +                return false;
615 +        }
616 +
617   #if DEBUG
618          printf("%08x: %s %s access", *nip_p,
619                     instr.transfer_size == SIZE_BYTE ? "byte" : instr.transfer_size == SIZE_WORD ? "word" : "long",
620 <                   instr.transfer_type == TYPE_LOAD ? "read" : "write");
620 >                   instr.transfer_type == SIGSEGV_TRANSFER_LOAD ? "read" : "write");
621          
622          if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
623                  printf(" r%d (ra = %08x)\n", instr.ra, instr.addr);
624 <        if (instr.transfer_type == TYPE_LOAD)
624 >        if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
625                  printf(" r%d (rd = 0)\n", instr.rd);
626   #endif
627          
628          if (instr.addr_mode == MODE_U || instr.addr_mode == MODE_UX)
629                  regs[instr.ra] = instr.addr;
630 <        if (instr.transfer_type == TYPE_LOAD)
630 >        if (instr.transfer_type == SIGSEGV_TRANSFER_LOAD)
631                  regs[instr.rd] = 0;
632          
633          *nip_p += 4;
# Line 644 | Line 666 | static void sigsegv_handler(SIGSEGV_FAUL
666                  fault_recovered = true;
667          }
668   #if HAVE_SIGSEGV_SKIP_INSTRUCTION
669 <        else if (sigsegv_ignore_fault) {
669 >        else if (sigsegv_ignore_ranges.size() > 0) {
670                  // Call the instruction skipper with the register file available
671                  if (SIGSEGV_SKIP_INSTRUCTION(SIGSEGV_REGISTER_FILE))
672                          fault_recovered = true;
# Line 674 | Line 696 | static bool sigsegv_do_install_handler(i
696   {
697          // Setup SIGSEGV handler to process writes to frame buffer
698   #ifdef HAVE_SIGACTION
699 <        struct sigaction vosf_sa;
700 <        sigemptyset(&vosf_sa.sa_mask);
701 <        vosf_sa.sa_sigaction = sigsegv_handler;
702 <        vosf_sa.sa_flags = SA_SIGINFO;
703 <        return (sigaction(sig, &vosf_sa, 0) == 0);
699 >        struct sigaction sigsegv_sa;
700 >        sigemptyset(&sigsegv_sa.sa_mask);
701 >        sigsegv_sa.sa_sigaction = sigsegv_handler;
702 >        sigsegv_sa.sa_flags = SA_SIGINFO;
703 >        return (sigaction(sig, &sigsegv_sa, 0) == 0);
704   #else
705          return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
706   #endif
# Line 690 | Line 712 | static bool sigsegv_do_install_handler(i
712   {
713          // Setup SIGSEGV handler to process writes to frame buffer
714   #ifdef HAVE_SIGACTION
715 <        struct sigaction vosf_sa;
716 <        sigemptyset(&vosf_sa.sa_mask);
717 <        vosf_sa.sa_handler = (signal_handler)sigsegv_handler;
715 >        struct sigaction sigsegv_sa;
716 >        sigemptyset(&sigsegv_sa.sa_mask);
717 >        sigsegv_sa.sa_handler = (signal_handler)sigsegv_handler;
718 >        sigsegv_sa.sa_flags = 0;
719   #if !EMULATED_68K && defined(__NetBSD__)
720 <        sigaddset(&vosf_sa.sa_mask, SIGALRM);
721 <        vosf_sa.sa_flags = SA_ONSTACK;
699 < #else
700 <        vosf_sa.sa_flags = 0;
720 >        sigaddset(&sigsegv_sa.sa_mask, SIGALRM);
721 >        sigsegv_sa.sa_flags |= SA_ONSTACK;
722   #endif
723 <        return (sigaction(sig, &vosf_sa, 0) == 0);
723 >        return (sigaction(sig, &sigsegv_sa, 0) == 0);
724   #else
725          return (signal(sig, (signal_handler)sigsegv_handler) != SIG_ERR);
726   #endif
# Line 738 | Line 759 | void sigsegv_deinstall_handler(void)
759  
760  
761   /*
762 < *  SIGSEGV ignore state modifier
762 > *  Add SIGSEGV ignore range
763   */
764  
765 < void sigsegv_set_ignore_state(bool ignore_fault)
765 > void sigsegv_add_ignore_range(sigsegv_address_t address, unsigned long length, int transfer_type)
766   {
767 <        sigsegv_ignore_fault = ignore_fault;
767 >        ignore_range_t ignore_range;
768 >        ignore_range.start = address;
769 >        ignore_range.length = length;
770 >        ignore_range.transfer_type = transfer_type;
771 >        sigsegv_ignore_ranges.push_front(ignore_range);
772 > }
773 >
774 >
775 > /*
776 > *  Remove SIGSEGV ignore range. Range must match installed one, otherwise FALSE is returned.
777 > */
778 >
779 > bool sigsegv_remove_ignore_range(sigsegv_address_t address, unsigned long length, int transfer_type)
780 > {
781 >        ignore_range_list_t::iterator it;
782 >        for (it = sigsegv_ignore_ranges.begin(); it != sigsegv_ignore_ranges.end(); it++)
783 >                if (it->start == address && it->length == length && ((it->transfer_type & transfer_type) == transfer_type))
784 >                        break;
785 >
786 >        if (it != sigsegv_ignore_ranges.end()) {
787 >                if (it->transfer_type != transfer_type)
788 >                        it->transfer_type &= ~transfer_type;
789 >                else
790 >                        sigsegv_ignore_ranges.erase(it);
791 >                return true;
792 >        }
793 >
794 >        return false;
795   }
796  
797  
# Line 823 | Line 871 | int main(void)
871          if (vm_protect((char *)page, page_size, VM_PAGE_NOACCESS) < 0)
872                  return 1;
873          
874 <        sigsegv_set_ignore_state(true);
874 >        sigsegv_add_ignore_range((char *)page, page_size, SIGSEGV_TRANSFER_LOAD | SIGSEGV_TRANSFER_STORE);
875  
876   #define TEST_SKIP_INSTRUCTION(TYPE) do {                                \
877                  const unsigned int TAG = 0x12345678;                    \

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines