Release 950122
[wine] / debugger / break.c
1
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <sys/mman.h>
5 #ifdef linux
6 #include <sys/utsname.h>
7 #endif
8 #include <windows.h>
9
10 #define N_BP 25
11
12 extern int dbg_mode;
13
14 struct wine_bp{
15   unsigned long addr;
16   unsigned long next_addr;
17   char in_use;
18   char enabled;
19   unsigned char databyte;
20 };
21
22 static struct wine_bp wbp[N_BP] = {{0,},};
23
24 static int current_bp = -1;
25 static int cont_mode=0; /* 0 - continuous execution
26                            1 - advancing after breakpoint
27                            2 - single step - not implemented
28                         */
29
30 void info_break(void)
31 {
32   int j;
33   fprintf(stderr,"Breakpoint status\n");
34   for(j=0; j<N_BP; j++)
35     if(wbp[j].in_use)
36       fprintf(stderr,"%d: %c %8lx\n", j, (wbp[j].enabled ? 'y' : 'n'),
37               wbp[j].addr);
38 }
39
40 void disable_break(int bpnum)
41 {
42   if(bpnum >= N_BP || bpnum < 0)
43     fprintf(stderr,"Breakpoint number out of range\n");
44
45   wbp[bpnum].enabled = 0;
46 }
47
48 void enable_break(int bpnum)
49 {
50   if(bpnum >= N_BP || bpnum < 0)
51     fprintf(stderr,"Breakpoint number out of range\n");
52
53   wbp[bpnum].enabled = 1;
54 }
55
56 void add_break(unsigned long addr)
57 {
58   int j;
59   for(j=0; j<N_BP; j++)
60     if(!wbp[j].in_use)
61       {
62         wbp[j].in_use = 1;
63         wbp[j].enabled = 1;
64         wbp[j].addr = addr;
65         wbp[j].next_addr = 0;
66         return;
67       }
68   fprintf(stderr,"No more breakpoints\n");
69 }
70
71 static void bark()
72 {
73   static int barked=0;
74   if(barked)return;
75   barked=1;
76   perror("Sorry, can't set break point");
77 #ifdef linux
78   {struct utsname buf;
79   uname(&buf);
80   if(strcmp(buf.sysname,"Linux")==0)
81   {     if(strcmp(buf.release,"1.1.62")<0)
82           fprintf(stderr,"Your current Linux release is %s. "
83                 "You should upgrade to 1.1.62 or higher\n"
84                 "Alternatively, in /usr/src/linux/fs/exec.c,"
85                 " change MAP_SHARED to MAP_PRIVATE.\n", buf.release);
86   } else
87   fprintf(stderr,"Why did you compile for Linux, while your system is"
88    " actually %s?\n",buf.sysname);
89   }
90 #endif
91 }
92   
93 void insert_break(int flag)
94 {
95   unsigned char * pnt;
96   int j;
97
98   for(j=0; j<N_BP; j++)
99     if(wbp[j].enabled)
100       {
101         /* There are a couple of problems with this. On Linux prior to
102            1.1.62, this call fails (ENOACCESS) due to a bug in fs/exec.c.
103            This code is currently not tested at all on BSD.
104            How do I determine the page size in a more symbolic manner?
105            And why does mprotect need that start address of the page
106            in the first place?
107            Not that portability matters, this code is i386 only anyways...
108            How do I get the old protection in order to restore it later on?
109         */
110         if(mprotect((caddr_t)(wbp[j].addr & (~4095)), 4096, 
111           PROT_READ|PROT_WRITE|PROT_EXEC) == -1){
112             bark();
113             return;
114         }
115         pnt = (unsigned char *) wbp[j].addr;
116         if(flag) {
117           wbp[j].databyte = *pnt;
118           *pnt = 0xcc;  /* Change to an int 3 instruction */
119         } else {
120           *pnt = wbp[j].databyte;
121         }
122         mprotect((caddr_t)(wbp[j].addr & ~4095), 4096, PROT_READ|PROT_EXEC);
123       }
124 }
125
126 /* Get the breakpoint number that we broke upon */
127 int get_bpnum(unsigned int addr)
128 {
129   int j;
130
131   for(j=0; j<N_BP; j++)
132     if(wbp[j].enabled)
133       if(wbp[j].addr == addr) return j;
134
135   return -1;
136 }
137
138 void toggle_next(int num)
139 {
140    unsigned int addr;
141    addr=wbp[num].addr;
142    if(wbp[num].next_addr == 0)
143         wbp[num].next_addr=addr+print_insn(addr,addr,stderr,dbg_mode);
144    wbp[num].addr=wbp[num].next_addr;
145    wbp[num].next_addr=addr;
146 }
147
148 int should_continue(int bpnum)
149 {
150     if(bpnum<0)return 0;
151     toggle_next(bpnum);
152     if(bpnum==current_bp){
153         current_bp=-1;
154         cont_mode=0;
155         return 1;
156     }
157     cont_mode=1;
158     current_bp=bpnum;
159     return 0;
160 }