diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-12-16 17:20:38 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-12-16 17:20:38 +0000 |
commit | 0163111325009ea10979105508bb294d4d67680c (patch) | |
tree | af0c356024acfde96833b0b9d0c938560139f242 /shell/ash.c | |
parent | 9ad2cb3f1a3a8999df1d08422ed7cf01242158a5 (diff) | |
download | busybox-w32-0163111325009ea10979105508bb294d4d67680c.tar.gz busybox-w32-0163111325009ea10979105508bb294d4d67680c.tar.bz2 busybox-w32-0163111325009ea10979105508bb294d4d67680c.zip |
ash: reduce global data/bss usage
(add/remove: 4/29 grow/shrink: 76/21 up/down: 1007/-1713) Total: -706 bytes
text data bss dec hex filename
777206 1084 8976 787266 c0342 busybox_old
778077 908 7568 786553 c0079 busybox_unstripped
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 456 |
1 files changed, 277 insertions, 179 deletions
diff --git a/shell/ash.c b/shell/ash.c index 4c8a28911..f7604cf93 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -67,6 +67,13 @@ extern char **environ; | |||
67 | #endif | 67 | #endif |
68 | 68 | ||
69 | 69 | ||
70 | /* ============ Hash table sizes. Configurable. */ | ||
71 | |||
72 | #define VTABSIZE 39 | ||
73 | #define ATABSIZE 39 | ||
74 | #define CMDTABLESIZE 31 /* should be prime */ | ||
75 | |||
76 | |||
70 | /* ============ Misc helpers */ | 77 | /* ============ Misc helpers */ |
71 | 78 | ||
72 | #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) | 79 | #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) |
@@ -127,30 +134,10 @@ static char optlist[NOPTS] ALIGN1; | |||
127 | 134 | ||
128 | /* ============ Misc data */ | 135 | /* ============ Misc data */ |
129 | 136 | ||
130 | static char nullstr[1] ALIGN1; /* zero length string */ | ||
131 | static const char homestr[] ALIGN1 = "HOME"; | 137 | static const char homestr[] ALIGN1 = "HOME"; |
132 | static const char snlfmt[] ALIGN1 = "%s\n"; | 138 | static const char snlfmt[] ALIGN1 = "%s\n"; |
133 | static const char illnum[] ALIGN1 = "Illegal number: %s"; | 139 | static const char illnum[] ALIGN1 = "Illegal number: %s"; |
134 | 140 | ||
135 | static char *minusc; /* argument to -c option */ | ||
136 | |||
137 | /* pid of main shell */ | ||
138 | static int rootpid; | ||
139 | /* shell level: 0 for the main shell, 1 for its children, and so on */ | ||
140 | static int shlvl; | ||
141 | #define rootshell (!shlvl) | ||
142 | /* trap handler commands */ | ||
143 | static char *trap[NSIG]; | ||
144 | static smallint isloginsh; | ||
145 | /* current value of signal */ | ||
146 | static char sigmode[NSIG - 1]; | ||
147 | /* indicates specified signal received */ | ||
148 | static char gotsig[NSIG - 1]; | ||
149 | static char *arg0; /* value of $0 */ | ||
150 | |||
151 | |||
152 | /* ============ Interrupts / exceptions */ | ||
153 | |||
154 | /* | 141 | /* |
155 | * We enclose jmp_buf in a structure so that we can declare pointers to | 142 | * We enclose jmp_buf in a structure so that we can declare pointers to |
156 | * jump locations. The global variable handler contains the location to | 143 | * jump locations. The global variable handler contains the location to |
@@ -163,34 +150,84 @@ static char *arg0; /* value of $0 */ | |||
163 | struct jmploc { | 150 | struct jmploc { |
164 | jmp_buf loc; | 151 | jmp_buf loc; |
165 | }; | 152 | }; |
166 | static struct jmploc *exception_handler; | 153 | |
167 | static int exception; | 154 | struct globals_misc { |
168 | /* exceptions */ | 155 | /* pid of main shell */ |
156 | int rootpid; | ||
157 | /* shell level: 0 for the main shell, 1 for its children, and so on */ | ||
158 | int shlvl; | ||
159 | #define rootshell (!shlvl) | ||
160 | char *minusc; /* argument to -c option */ | ||
161 | |||
162 | char *curdir; // = nullstr; /* current working directory */ | ||
163 | char *physdir; // = nullstr; /* physical working directory */ | ||
164 | |||
165 | char *arg0; /* value of $0 */ | ||
166 | |||
167 | struct jmploc *exception_handler; | ||
168 | int exception; | ||
169 | /* exceptions */ | ||
169 | #define EXINT 0 /* SIGINT received */ | 170 | #define EXINT 0 /* SIGINT received */ |
170 | #define EXERROR 1 /* a generic error */ | 171 | #define EXERROR 1 /* a generic error */ |
171 | #define EXSHELLPROC 2 /* execute a shell procedure */ | 172 | #define EXSHELLPROC 2 /* execute a shell procedure */ |
172 | #define EXEXEC 3 /* command execution failed */ | 173 | #define EXEXEC 3 /* command execution failed */ |
173 | #define EXEXIT 4 /* exit the shell */ | 174 | #define EXEXIT 4 /* exit the shell */ |
174 | #define EXSIG 5 /* trapped signal in wait(1) */ | 175 | #define EXSIG 5 /* trapped signal in wait(1) */ |
175 | static volatile int suppressint; | 176 | volatile int suppressint; |
176 | static volatile sig_atomic_t intpending; | 177 | volatile sig_atomic_t intpending; |
177 | /* do we generate EXSIG events */ | 178 | /* do we generate EXSIG events */ |
178 | static int exsig; | 179 | int exsig; |
179 | /* last pending signal */ | 180 | /* last pending signal */ |
180 | static volatile sig_atomic_t pendingsig; | 181 | volatile sig_atomic_t pendingsig; |
181 | 182 | ||
182 | /* | 183 | /* trap handler commands */ |
183 | * Sigmode records the current value of the signal handlers for the various | 184 | char *trap[NSIG]; |
184 | * modes. A value of zero means that the current handler is not known. | 185 | smallint isloginsh; |
185 | * S_HARD_IGN indicates that the signal was ignored on entry to the shell, | 186 | char nullstr[1]; /* zero length string */ |
186 | */ | 187 | /* |
187 | 188 | * Sigmode records the current value of the signal handlers for the various | |
189 | * modes. A value of zero means that the current handler is not known. | ||
190 | * S_HARD_IGN indicates that the signal was ignored on entry to the shell, | ||
191 | */ | ||
192 | char sigmode[NSIG - 1]; | ||
188 | #define S_DFL 1 /* default signal handling (SIG_DFL) */ | 193 | #define S_DFL 1 /* default signal handling (SIG_DFL) */ |
189 | #define S_CATCH 2 /* signal is caught */ | 194 | #define S_CATCH 2 /* signal is caught */ |
190 | #define S_IGN 3 /* signal is ignored (SIG_IGN) */ | 195 | #define S_IGN 3 /* signal is ignored (SIG_IGN) */ |
191 | #define S_HARD_IGN 4 /* signal is ignored permenantly */ | 196 | #define S_HARD_IGN 4 /* signal is ignored permenantly */ |
192 | #define S_RESET 5 /* temporary - to reset a hard ignored sig */ | 197 | #define S_RESET 5 /* temporary - to reset a hard ignored sig */ |
193 | 198 | ||
199 | /* indicates specified signal received */ | ||
200 | char gotsig[NSIG - 1]; | ||
201 | }; | ||
202 | /* Make it reside in writable memory, yet make compiler understand that it is not going to change. */ | ||
203 | static struct globals_misc *const ptr_to_globals_misc __attribute__ ((section (".data"))); | ||
204 | #define G_misc (*ptr_to_globals_misc) | ||
205 | #define rootpid (G_misc.rootpid ) | ||
206 | #define shlvl (G_misc.shlvl ) | ||
207 | #define minusc (G_misc.minusc ) | ||
208 | #define curdir (G_misc.curdir ) | ||
209 | #define physdir (G_misc.physdir ) | ||
210 | #define arg0 (G_misc.arg0 ) | ||
211 | #define exception_handler (G_misc.exception_handler) | ||
212 | #define exception (G_misc.exception ) | ||
213 | #define suppressint (G_misc.suppressint ) | ||
214 | #define intpending (G_misc.intpending ) | ||
215 | #define exsig (G_misc.exsig ) | ||
216 | #define pendingsig (G_misc.pendingsig ) | ||
217 | #define trap (G_misc.trap ) | ||
218 | #define isloginsh (G_misc.isloginsh) | ||
219 | #define nullstr (G_misc.nullstr ) | ||
220 | #define sigmode (G_misc.sigmode ) | ||
221 | #define gotsig (G_misc.gotsig ) | ||
222 | #define INIT_G_misc() do { \ | ||
223 | (*(struct globals_misc**)&ptr_to_globals_misc) = xzalloc(sizeof(G_misc)); \ | ||
224 | curdir = nullstr; \ | ||
225 | physdir = nullstr; \ | ||
226 | } while (0) | ||
227 | |||
228 | |||
229 | /* ============ Interrupts / exceptions */ | ||
230 | |||
194 | /* | 231 | /* |
195 | * These macros allow the user to suspend the handling of interrupt signals | 232 | * These macros allow the user to suspend the handling of interrupt signals |
196 | * over a period of time. This is similar to SIGHOLD to or sigblock, but | 233 | * over a period of time. This is similar to SIGHOLD to or sigblock, but |
@@ -1090,7 +1127,7 @@ enum { | |||
1090 | * on many machines. */ | 1127 | * on many machines. */ |
1091 | SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1, | 1128 | SHELL_SIZE = sizeof(union {int i; char *cp; double d; }) - 1, |
1092 | /* Minimum size of a block */ | 1129 | /* Minimum size of a block */ |
1093 | MINSIZE = SHELL_ALIGN(504), | 1130 | MINSIZE = SHELL_ALIGN(504), |
1094 | }; | 1131 | }; |
1095 | 1132 | ||
1096 | struct stack_block { | 1133 | struct stack_block { |
@@ -1105,16 +1142,38 @@ struct stackmark { | |||
1105 | struct stackmark *marknext; | 1142 | struct stackmark *marknext; |
1106 | }; | 1143 | }; |
1107 | 1144 | ||
1108 | static struct stack_block stackbase; | ||
1109 | static struct stack_block *stackp = &stackbase; | ||
1110 | static struct stackmark *markp; | ||
1111 | static char *stacknxt = stackbase.space; | ||
1112 | static size_t stacknleft = MINSIZE; | ||
1113 | static char *sstrend = stackbase.space + MINSIZE; | ||
1114 | static int herefd = -1; | ||
1115 | 1145 | ||
1116 | #define stackblock() ((void *)stacknxt) | 1146 | struct globals_memstack { |
1117 | #define stackblocksize() stacknleft | 1147 | struct stack_block *g_stackp; // = &stackbase; |
1148 | struct stackmark *markp; | ||
1149 | char *g_stacknxt; // = stackbase.space; | ||
1150 | char *sstrend; // = stackbase.space + MINSIZE; | ||
1151 | size_t g_stacknleft; // = MINSIZE; | ||
1152 | int herefd; // = -1; | ||
1153 | struct stack_block stackbase; | ||
1154 | }; | ||
1155 | /* Make it reside in writable memory, yet make compiler understand that it is not going to change. */ | ||
1156 | static struct globals_memstack *const ptr_to_globals_memstack __attribute__ ((section (".data"))); | ||
1157 | #define G_memstack (*ptr_to_globals_memstack) | ||
1158 | #define g_stackp (G_memstack.g_stackp ) | ||
1159 | #define markp (G_memstack.markp ) | ||
1160 | #define g_stacknxt (G_memstack.g_stacknxt ) | ||
1161 | #define sstrend (G_memstack.sstrend ) | ||
1162 | #define g_stacknleft (G_memstack.g_stacknleft) | ||
1163 | #define herefd (G_memstack.herefd ) | ||
1164 | #define stackbase (G_memstack.stackbase ) | ||
1165 | #define INIT_G_memstack() do { \ | ||
1166 | (*(struct globals_memstack**)&ptr_to_globals_memstack) = xzalloc(sizeof(G_memstack)); \ | ||
1167 | g_stackp = &stackbase; \ | ||
1168 | g_stacknxt = stackbase.space; \ | ||
1169 | g_stacknleft = MINSIZE; \ | ||
1170 | sstrend = stackbase.space + MINSIZE; \ | ||
1171 | herefd = -1; \ | ||
1172 | } while (0) | ||
1173 | |||
1174 | #define stackblock() ((void *)g_stacknxt) | ||
1175 | #define stackblocksize() g_stacknleft | ||
1176 | |||
1118 | 1177 | ||
1119 | static void * | 1178 | static void * |
1120 | ckrealloc(void * p, size_t nbytes) | 1179 | ckrealloc(void * p, size_t nbytes) |
@@ -1158,7 +1217,7 @@ stalloc(size_t nbytes) | |||
1158 | size_t aligned; | 1217 | size_t aligned; |
1159 | 1218 | ||
1160 | aligned = SHELL_ALIGN(nbytes); | 1219 | aligned = SHELL_ALIGN(nbytes); |
1161 | if (aligned > stacknleft) { | 1220 | if (aligned > g_stacknleft) { |
1162 | size_t len; | 1221 | size_t len; |
1163 | size_t blocksize; | 1222 | size_t blocksize; |
1164 | struct stack_block *sp; | 1223 | struct stack_block *sp; |
@@ -1171,16 +1230,16 @@ stalloc(size_t nbytes) | |||
1171 | ash_msg_and_raise_error(bb_msg_memory_exhausted); | 1230 | ash_msg_and_raise_error(bb_msg_memory_exhausted); |
1172 | INT_OFF; | 1231 | INT_OFF; |
1173 | sp = ckmalloc(len); | 1232 | sp = ckmalloc(len); |
1174 | sp->prev = stackp; | 1233 | sp->prev = g_stackp; |
1175 | stacknxt = sp->space; | 1234 | g_stacknxt = sp->space; |
1176 | stacknleft = blocksize; | 1235 | g_stacknleft = blocksize; |
1177 | sstrend = stacknxt + blocksize; | 1236 | sstrend = g_stacknxt + blocksize; |
1178 | stackp = sp; | 1237 | g_stackp = sp; |
1179 | INT_ON; | 1238 | INT_ON; |
1180 | } | 1239 | } |
1181 | p = stacknxt; | 1240 | p = g_stacknxt; |
1182 | stacknxt += aligned; | 1241 | g_stacknxt += aligned; |
1183 | stacknleft -= aligned; | 1242 | g_stacknleft -= aligned; |
1184 | return p; | 1243 | return p; |
1185 | } | 1244 | } |
1186 | 1245 | ||
@@ -1188,13 +1247,13 @@ static void | |||
1188 | stunalloc(void *p) | 1247 | stunalloc(void *p) |
1189 | { | 1248 | { |
1190 | #if DEBUG | 1249 | #if DEBUG |
1191 | if (!p || (stacknxt < (char *)p) || ((char *)p < stackp->space)) { | 1250 | if (!p || (g_stacknxt < (char *)p) || ((char *)p < g_stackp->space)) { |
1192 | write(2, "stunalloc\n", 10); | 1251 | write(2, "stunalloc\n", 10); |
1193 | abort(); | 1252 | abort(); |
1194 | } | 1253 | } |
1195 | #endif | 1254 | #endif |
1196 | stacknleft += stacknxt - (char *)p; | 1255 | g_stacknleft += g_stacknxt - (char *)p; |
1197 | stacknxt = p; | 1256 | g_stacknxt = p; |
1198 | } | 1257 | } |
1199 | 1258 | ||
1200 | /* | 1259 | /* |
@@ -1210,9 +1269,9 @@ ststrdup(const char *p) | |||
1210 | static void | 1269 | static void |
1211 | setstackmark(struct stackmark *mark) | 1270 | setstackmark(struct stackmark *mark) |
1212 | { | 1271 | { |
1213 | mark->stackp = stackp; | 1272 | mark->stackp = g_stackp; |
1214 | mark->stacknxt = stacknxt; | 1273 | mark->stacknxt = g_stacknxt; |
1215 | mark->stacknleft = stacknleft; | 1274 | mark->stacknleft = g_stacknleft; |
1216 | mark->marknext = markp; | 1275 | mark->marknext = markp; |
1217 | markp = mark; | 1276 | markp = mark; |
1218 | } | 1277 | } |
@@ -1227,13 +1286,13 @@ popstackmark(struct stackmark *mark) | |||
1227 | 1286 | ||
1228 | INT_OFF; | 1287 | INT_OFF; |
1229 | markp = mark->marknext; | 1288 | markp = mark->marknext; |
1230 | while (stackp != mark->stackp) { | 1289 | while (g_stackp != mark->stackp) { |
1231 | sp = stackp; | 1290 | sp = g_stackp; |
1232 | stackp = sp->prev; | 1291 | g_stackp = sp->prev; |
1233 | free(sp); | 1292 | free(sp); |
1234 | } | 1293 | } |
1235 | stacknxt = mark->stacknxt; | 1294 | g_stacknxt = mark->stacknxt; |
1236 | stacknleft = mark->stacknleft; | 1295 | g_stacknleft = mark->stacknleft; |
1237 | sstrend = mark->stacknxt + mark->stacknleft; | 1296 | sstrend = mark->stacknxt + mark->stacknleft; |
1238 | INT_ON; | 1297 | INT_ON; |
1239 | } | 1298 | } |
@@ -1252,13 +1311,13 @@ growstackblock(void) | |||
1252 | { | 1311 | { |
1253 | size_t newlen; | 1312 | size_t newlen; |
1254 | 1313 | ||
1255 | newlen = stacknleft * 2; | 1314 | newlen = g_stacknleft * 2; |
1256 | if (newlen < stacknleft) | 1315 | if (newlen < g_stacknleft) |
1257 | ash_msg_and_raise_error(bb_msg_memory_exhausted); | 1316 | ash_msg_and_raise_error(bb_msg_memory_exhausted); |
1258 | if (newlen < 128) | 1317 | if (newlen < 128) |
1259 | newlen += 128; | 1318 | newlen += 128; |
1260 | 1319 | ||
1261 | if (stacknxt == stackp->space && stackp != &stackbase) { | 1320 | if (g_stacknxt == g_stackp->space && g_stackp != &stackbase) { |
1262 | struct stack_block *oldstackp; | 1321 | struct stack_block *oldstackp; |
1263 | struct stackmark *xmark; | 1322 | struct stackmark *xmark; |
1264 | struct stack_block *sp; | 1323 | struct stack_block *sp; |
@@ -1266,15 +1325,15 @@ growstackblock(void) | |||
1266 | size_t grosslen; | 1325 | size_t grosslen; |
1267 | 1326 | ||
1268 | INT_OFF; | 1327 | INT_OFF; |
1269 | oldstackp = stackp; | 1328 | oldstackp = g_stackp; |
1270 | sp = stackp; | 1329 | sp = g_stackp; |
1271 | prevstackp = sp->prev; | 1330 | prevstackp = sp->prev; |
1272 | grosslen = newlen + sizeof(struct stack_block) - MINSIZE; | 1331 | grosslen = newlen + sizeof(struct stack_block) - MINSIZE; |
1273 | sp = ckrealloc(sp, grosslen); | 1332 | sp = ckrealloc(sp, grosslen); |
1274 | sp->prev = prevstackp; | 1333 | sp->prev = prevstackp; |
1275 | stackp = sp; | 1334 | g_stackp = sp; |
1276 | stacknxt = sp->space; | 1335 | g_stacknxt = sp->space; |
1277 | stacknleft = newlen; | 1336 | g_stacknleft = newlen; |
1278 | sstrend = sp->space + newlen; | 1337 | sstrend = sp->space + newlen; |
1279 | 1338 | ||
1280 | /* | 1339 | /* |
@@ -1283,20 +1342,20 @@ growstackblock(void) | |||
1283 | */ | 1342 | */ |
1284 | xmark = markp; | 1343 | xmark = markp; |
1285 | while (xmark != NULL && xmark->stackp == oldstackp) { | 1344 | while (xmark != NULL && xmark->stackp == oldstackp) { |
1286 | xmark->stackp = stackp; | 1345 | xmark->stackp = g_stackp; |
1287 | xmark->stacknxt = stacknxt; | 1346 | xmark->stacknxt = g_stacknxt; |
1288 | xmark->stacknleft = stacknleft; | 1347 | xmark->stacknleft = g_stacknleft; |
1289 | xmark = xmark->marknext; | 1348 | xmark = xmark->marknext; |
1290 | } | 1349 | } |
1291 | INT_ON; | 1350 | INT_ON; |
1292 | } else { | 1351 | } else { |
1293 | char *oldspace = stacknxt; | 1352 | char *oldspace = g_stacknxt; |
1294 | int oldlen = stacknleft; | 1353 | int oldlen = g_stacknleft; |
1295 | char *p = stalloc(newlen); | 1354 | char *p = stalloc(newlen); |
1296 | 1355 | ||
1297 | /* free the space we just allocated */ | 1356 | /* free the space we just allocated */ |
1298 | stacknxt = memcpy(p, oldspace, oldlen); | 1357 | g_stacknxt = memcpy(p, oldspace, oldlen); |
1299 | stacknleft += newlen; | 1358 | g_stacknleft += newlen; |
1300 | } | 1359 | } |
1301 | } | 1360 | } |
1302 | 1361 | ||
@@ -1304,8 +1363,8 @@ static void | |||
1304 | grabstackblock(size_t len) | 1363 | grabstackblock(size_t len) |
1305 | { | 1364 | { |
1306 | len = SHELL_ALIGN(len); | 1365 | len = SHELL_ALIGN(len); |
1307 | stacknxt += len; | 1366 | g_stacknxt += len; |
1308 | stacknleft -= len; | 1367 | g_stacknleft -= len; |
1309 | } | 1368 | } |
1310 | 1369 | ||
1311 | /* | 1370 | /* |
@@ -1343,7 +1402,7 @@ growstackstr(void) | |||
1343 | static char * | 1402 | static char * |
1344 | makestrspace(size_t newlen, char *p) | 1403 | makestrspace(size_t newlen, char *p) |
1345 | { | 1404 | { |
1346 | size_t len = p - stacknxt; | 1405 | size_t len = p - g_stacknxt; |
1347 | size_t size = stackblocksize(); | 1406 | size_t size = stackblocksize(); |
1348 | 1407 | ||
1349 | for (;;) { | 1408 | for (;;) { |
@@ -1568,41 +1627,26 @@ static unsigned long rseed; | |||
1568 | 1627 | ||
1569 | /* ============ Shell variables */ | 1628 | /* ============ Shell variables */ |
1570 | 1629 | ||
1571 | /* flags */ | 1630 | /* |
1572 | #define VEXPORT 0x01 /* variable is exported */ | 1631 | * The parsefile structure pointed to by the global variable parsefile |
1573 | #define VREADONLY 0x02 /* variable cannot be modified */ | 1632 | * contains information about the current file being read. |
1574 | #define VSTRFIXED 0x04 /* variable struct is statically allocated */ | 1633 | */ |
1575 | #define VTEXTFIXED 0x08 /* text is statically allocated */ | 1634 | struct redirtab { |
1576 | #define VSTACK 0x10 /* text is allocated on the stack */ | 1635 | struct redirtab *next; |
1577 | #define VUNSET 0x20 /* the variable is not set */ | 1636 | int renamed[10]; |
1578 | #define VNOFUNC 0x40 /* don't call the callback function */ | 1637 | int nullredirs; |
1579 | #define VNOSET 0x80 /* do not set variable - just readonly test */ | 1638 | }; |
1580 | #define VNOSAVE 0x100 /* when text is on the heap before setvareq */ | ||
1581 | #ifdef DYNAMIC_VAR | ||
1582 | # define VDYNAMIC 0x200 /* dynamic variable */ | ||
1583 | #else | ||
1584 | # define VDYNAMIC 0 | ||
1585 | #endif | ||
1586 | |||
1587 | #ifdef IFS_BROKEN | ||
1588 | static const char defifsvar[] ALIGN1 = "IFS= \t\n"; | ||
1589 | #define defifs (defifsvar + 4) | ||
1590 | #else | ||
1591 | static const char defifs[] ALIGN1 = " \t\n"; | ||
1592 | #endif | ||
1593 | 1639 | ||
1594 | struct shparam { | 1640 | struct shparam { |
1595 | int nparam; /* # of positional parameters (without $0) */ | 1641 | int nparam; /* # of positional parameters (without $0) */ |
1596 | unsigned char malloc; /* if parameter list dynamically allocated */ | ||
1597 | char **p; /* parameter list */ | ||
1598 | #if ENABLE_ASH_GETOPTS | 1642 | #if ENABLE_ASH_GETOPTS |
1599 | int optind; /* next parameter to be processed by getopts */ | 1643 | int optind; /* next parameter to be processed by getopts */ |
1600 | int optoff; /* used by getopts */ | 1644 | int optoff; /* used by getopts */ |
1601 | #endif | 1645 | #endif |
1646 | unsigned char malloced; /* if parameter list dynamically allocated */ | ||
1647 | char **p; /* parameter list */ | ||
1602 | }; | 1648 | }; |
1603 | 1649 | ||
1604 | static struct shparam shellparam; /* $@ current positional parameters */ | ||
1605 | |||
1606 | /* | 1650 | /* |
1607 | * Free the list of positional parameters. | 1651 | * Free the list of positional parameters. |
1608 | */ | 1652 | */ |
@@ -1611,7 +1655,7 @@ freeparam(volatile struct shparam *param) | |||
1611 | { | 1655 | { |
1612 | char **ap; | 1656 | char **ap; |
1613 | 1657 | ||
1614 | if (param->malloc) { | 1658 | if (param->malloced) { |
1615 | for (ap = param->p; *ap; ap++) | 1659 | for (ap = param->p; *ap; ap++) |
1616 | free(*ap); | 1660 | free(*ap); |
1617 | free(param->p); | 1661 | free(param->p); |
@@ -1619,12 +1663,7 @@ freeparam(volatile struct shparam *param) | |||
1619 | } | 1663 | } |
1620 | 1664 | ||
1621 | #if ENABLE_ASH_GETOPTS | 1665 | #if ENABLE_ASH_GETOPTS |
1622 | static void | 1666 | static void getoptsreset(const char *value); |
1623 | getoptsreset(const char *value) | ||
1624 | { | ||
1625 | shellparam.optind = number(value); | ||
1626 | shellparam.optoff = -1; | ||
1627 | } | ||
1628 | #endif | 1667 | #endif |
1629 | 1668 | ||
1630 | struct var { | 1669 | struct var { |
@@ -1642,7 +1681,31 @@ struct localvar { | |||
1642 | const char *text; /* saved text */ | 1681 | const char *text; /* saved text */ |
1643 | }; | 1682 | }; |
1644 | 1683 | ||
1645 | /* Forward decls for varinit[] */ | 1684 | /* flags */ |
1685 | #define VEXPORT 0x01 /* variable is exported */ | ||
1686 | #define VREADONLY 0x02 /* variable cannot be modified */ | ||
1687 | #define VSTRFIXED 0x04 /* variable struct is statically allocated */ | ||
1688 | #define VTEXTFIXED 0x08 /* text is statically allocated */ | ||
1689 | #define VSTACK 0x10 /* text is allocated on the stack */ | ||
1690 | #define VUNSET 0x20 /* the variable is not set */ | ||
1691 | #define VNOFUNC 0x40 /* don't call the callback function */ | ||
1692 | #define VNOSET 0x80 /* do not set variable - just readonly test */ | ||
1693 | #define VNOSAVE 0x100 /* when text is on the heap before setvareq */ | ||
1694 | #ifdef DYNAMIC_VAR | ||
1695 | # define VDYNAMIC 0x200 /* dynamic variable */ | ||
1696 | #else | ||
1697 | # define VDYNAMIC 0 | ||
1698 | #endif | ||
1699 | |||
1700 | #ifdef IFS_BROKEN | ||
1701 | static const char defifsvar[] ALIGN1 = "IFS= \t\n"; | ||
1702 | #define defifs (defifsvar + 4) | ||
1703 | #else | ||
1704 | static const char defifs[] ALIGN1 = " \t\n"; | ||
1705 | #endif | ||
1706 | |||
1707 | |||
1708 | /* Need to be before varinit_data[] */ | ||
1646 | #if ENABLE_LOCALE_SUPPORT | 1709 | #if ENABLE_LOCALE_SUPPORT |
1647 | static void | 1710 | static void |
1648 | change_lc_all(const char *value) | 1711 | change_lc_all(const char *value) |
@@ -1666,46 +1729,78 @@ static void changepath(const char *); | |||
1666 | static void change_random(const char *); | 1729 | static void change_random(const char *); |
1667 | #endif | 1730 | #endif |
1668 | 1731 | ||
1669 | static struct var varinit[] = { | 1732 | static const struct { |
1733 | int flags; | ||
1734 | const char *text; | ||
1735 | void (*func)(const char *); | ||
1736 | } varinit_data[] = { | ||
1670 | #ifdef IFS_BROKEN | 1737 | #ifdef IFS_BROKEN |
1671 | { NULL, VSTRFIXED|VTEXTFIXED, defifsvar, NULL }, | 1738 | { VSTRFIXED|VTEXTFIXED , defifsvar , NULL }, |
1672 | #else | 1739 | #else |
1673 | { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0", NULL }, | 1740 | { VSTRFIXED|VTEXTFIXED|VUNSET, "IFS\0" , NULL }, |
1674 | #endif | 1741 | #endif |
1675 | #if ENABLE_ASH_MAIL | 1742 | #if ENABLE_ASH_MAIL |
1676 | { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0", changemail }, | 1743 | { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL\0" , changemail }, |
1677 | { NULL, VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, | 1744 | { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH\0", changemail }, |
1678 | #endif | 1745 | #endif |
1679 | { NULL, VSTRFIXED|VTEXTFIXED, bb_PATH_root_path, changepath }, | 1746 | { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath }, |
1680 | { NULL, VSTRFIXED|VTEXTFIXED, "PS1=$ ", NULL }, | 1747 | { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL }, |
1681 | { NULL, VSTRFIXED|VTEXTFIXED, "PS2=> ", NULL }, | 1748 | { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL }, |
1682 | { NULL, VSTRFIXED|VTEXTFIXED, "PS4=+ ", NULL }, | 1749 | { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL }, |
1683 | #if ENABLE_ASH_GETOPTS | 1750 | #if ENABLE_ASH_GETOPTS |
1684 | { NULL, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, | 1751 | { VSTRFIXED|VTEXTFIXED , "OPTIND=1" , getoptsreset }, |
1685 | #endif | 1752 | #endif |
1686 | #if ENABLE_ASH_RANDOM_SUPPORT | 1753 | #if ENABLE_ASH_RANDOM_SUPPORT |
1687 | { NULL, VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, | 1754 | { VSTRFIXED|VTEXTFIXED|VUNSET|VDYNAMIC, "RANDOM\0", change_random }, |
1688 | #endif | 1755 | #endif |
1689 | #if ENABLE_LOCALE_SUPPORT | 1756 | #if ENABLE_LOCALE_SUPPORT |
1690 | { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_ALL\0", change_lc_all }, | 1757 | { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_ALL\0" , change_lc_all }, |
1691 | { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "LC_CTYPE\0", change_lc_ctype }, | 1758 | { VSTRFIXED|VTEXTFIXED|VUNSET, "LC_CTYPE\0", change_lc_ctype }, |
1692 | #endif | 1759 | #endif |
1693 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY | 1760 | #if ENABLE_FEATURE_EDITING_SAVEHISTORY |
1694 | { NULL, VSTRFIXED | VTEXTFIXED | VUNSET, "HISTFILE\0", NULL }, | 1761 | { VSTRFIXED|VTEXTFIXED|VUNSET, "HISTFILE\0", NULL }, |
1695 | #endif | 1762 | #endif |
1696 | }; | 1763 | }; |
1697 | 1764 | ||
1698 | #define vifs varinit[0] | 1765 | |
1766 | struct globals_var { | ||
1767 | struct shparam shellparam; /* $@ current positional parameters */ | ||
1768 | struct redirtab *redirlist; | ||
1769 | int g_nullredirs; | ||
1770 | int preverrout_fd; /* save fd2 before print debug if xflag is set. */ | ||
1771 | struct var *vartab[VTABSIZE]; | ||
1772 | struct var varinit[ARRAY_SIZE(varinit_data)]; | ||
1773 | }; | ||
1774 | /* Make it reside in writable memory, yet make compiler understand that it is not going to change. */ | ||
1775 | static struct globals_var *const ptr_to_globals_var __attribute__ ((section (".data"))); | ||
1776 | #define G_var (*ptr_to_globals_var) | ||
1777 | #define shellparam (G_var.shellparam ) | ||
1778 | #define redirlist (G_var.redirlist ) | ||
1779 | #define g_nullredirs (G_var.g_nullredirs ) | ||
1780 | #define preverrout_fd (G_var.preverrout_fd) | ||
1781 | #define vartab (G_var.vartab ) | ||
1782 | #define varinit (G_var.varinit ) | ||
1783 | #define INIT_G_var() do { \ | ||
1784 | int i; \ | ||
1785 | (*(struct globals_var**)&ptr_to_globals_var) = xzalloc(sizeof(G_var)); \ | ||
1786 | for (i = 0; i < ARRAY_SIZE(varinit_data); i++) { \ | ||
1787 | varinit[i].flags = varinit_data[i].flags; \ | ||
1788 | varinit[i].text = varinit_data[i].text; \ | ||
1789 | varinit[i].func = varinit_data[i].func; \ | ||
1790 | } \ | ||
1791 | } while (0) | ||
1792 | |||
1793 | #define vifs varinit[0] | ||
1699 | #if ENABLE_ASH_MAIL | 1794 | #if ENABLE_ASH_MAIL |
1700 | #define vmail (&vifs)[1] | 1795 | #define vmail (&vifs)[1] |
1701 | #define vmpath (&vmail)[1] | 1796 | #define vmpath (&vmail)[1] |
1702 | #else | 1797 | #else |
1703 | #define vmpath vifs | 1798 | #define vmpath vifs |
1704 | #endif | 1799 | #endif |
1705 | #define vpath (&vmpath)[1] | 1800 | #define vpath (&vmpath)[1] |
1706 | #define vps1 (&vpath)[1] | 1801 | #define vps1 (&vpath)[1] |
1707 | #define vps2 (&vps1)[1] | 1802 | #define vps2 (&vps1)[1] |
1708 | #define vps4 (&vps2)[1] | 1803 | #define vps4 (&vps2)[1] |
1709 | #define voptind (&vps4)[1] | 1804 | #define voptind (&vps4)[1] |
1710 | #if ENABLE_ASH_GETOPTS | 1805 | #if ENABLE_ASH_GETOPTS |
1711 | #define vrandom (&voptind)[1] | 1806 | #define vrandom (&voptind)[1] |
@@ -1730,27 +1825,19 @@ static struct var varinit[] = { | |||
1730 | 1825 | ||
1731 | #define mpathset() ((vmpath.flags & VUNSET) == 0) | 1826 | #define mpathset() ((vmpath.flags & VUNSET) == 0) |
1732 | 1827 | ||
1733 | /* | ||
1734 | * The parsefile structure pointed to by the global variable parsefile | ||
1735 | * contains information about the current file being read. | ||
1736 | */ | ||
1737 | struct redirtab { | ||
1738 | struct redirtab *next; | ||
1739 | int renamed[10]; | ||
1740 | int nullredirs; | ||
1741 | }; | ||
1742 | |||
1743 | static struct redirtab *redirlist; | ||
1744 | static int nullredirs; | ||
1745 | static int preverrout_fd; /* save fd2 before print debug if xflag is set. */ | ||
1746 | |||
1747 | #define VTABSIZE 39 | ||
1748 | |||
1749 | static struct var *vartab[VTABSIZE]; | ||
1750 | 1828 | ||
1751 | #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) | 1829 | #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) |
1752 | #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) | 1830 | #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) |
1753 | 1831 | ||
1832 | #if ENABLE_ASH_GETOPTS | ||
1833 | static void | ||
1834 | getoptsreset(const char *value) | ||
1835 | { | ||
1836 | shellparam.optind = number(value); | ||
1837 | shellparam.optoff = -1; | ||
1838 | } | ||
1839 | #endif | ||
1840 | |||
1754 | /* | 1841 | /* |
1755 | * Return of a legal variable name (a letter or underscore followed by zero or | 1842 | * Return of a legal variable name (a letter or underscore followed by zero or |
1756 | * more letters, underscores, and digits). | 1843 | * more letters, underscores, and digits). |
@@ -2221,9 +2308,6 @@ setprompt(int whichprompt) | |||
2221 | 2308 | ||
2222 | static int docd(const char *, int); | 2309 | static int docd(const char *, int); |
2223 | 2310 | ||
2224 | static char *curdir = nullstr; /* current working directory */ | ||
2225 | static char *physdir = nullstr; /* physical working directory */ | ||
2226 | |||
2227 | static int | 2311 | static int |
2228 | cdopt(void) | 2312 | cdopt(void) |
2229 | { | 2313 | { |
@@ -2310,7 +2394,7 @@ updatepwd(const char *dir) | |||
2310 | static char * | 2394 | static char * |
2311 | getpwd(void) | 2395 | getpwd(void) |
2312 | { | 2396 | { |
2313 | char *dir = getcwd(0, 0); | 2397 | char *dir = getcwd(NULL, 0); /* huh, using glibc extension? */ |
2314 | return dir ? dir : nullstr; | 2398 | return dir ? dir : nullstr; |
2315 | } | 2399 | } |
2316 | 2400 | ||
@@ -2903,8 +2987,6 @@ static const char syntax_index_table[258] = { | |||
2903 | #define ALIASINUSE 1 | 2987 | #define ALIASINUSE 1 |
2904 | #define ALIASDEAD 2 | 2988 | #define ALIASDEAD 2 |
2905 | 2989 | ||
2906 | #define ATABSIZE 39 | ||
2907 | |||
2908 | struct alias { | 2990 | struct alias { |
2909 | struct alias *next; | 2991 | struct alias *next; |
2910 | char *name; | 2992 | char *name; |
@@ -2912,7 +2994,12 @@ struct alias { | |||
2912 | int flag; | 2994 | int flag; |
2913 | }; | 2995 | }; |
2914 | 2996 | ||
2915 | static struct alias *atab[ATABSIZE]; | 2997 | |
2998 | static struct alias **atab; // [ATABSIZE]; | ||
2999 | #define INIT_G_alias() do { \ | ||
3000 | atab = xzalloc(ATABSIZE * sizeof(atab[0])); \ | ||
3001 | } while (0) | ||
3002 | |||
2916 | 3003 | ||
2917 | static struct alias ** | 3004 | static struct alias ** |
2918 | __lookupalias(const char *name) { | 3005 | __lookupalias(const char *name) { |
@@ -4797,7 +4884,7 @@ redirect(union node *redir, int flags) | |||
4797 | int fd; | 4884 | int fd; |
4798 | int newfd; | 4885 | int newfd; |
4799 | 4886 | ||
4800 | nullredirs++; | 4887 | g_nullredirs++; |
4801 | if (!redir) { | 4888 | if (!redir) { |
4802 | return; | 4889 | return; |
4803 | } | 4890 | } |
@@ -4807,10 +4894,10 @@ redirect(union node *redir, int flags) | |||
4807 | sv = ckmalloc(sizeof(*sv)); | 4894 | sv = ckmalloc(sizeof(*sv)); |
4808 | sv->next = redirlist; | 4895 | sv->next = redirlist; |
4809 | redirlist = sv; | 4896 | redirlist = sv; |
4810 | sv->nullredirs = nullredirs - 1; | 4897 | sv->nullredirs = g_nullredirs - 1; |
4811 | for (i = 0; i < 10; i++) | 4898 | for (i = 0; i < 10; i++) |
4812 | sv->renamed[i] = EMPTY; | 4899 | sv->renamed[i] = EMPTY; |
4813 | nullredirs = 0; | 4900 | g_nullredirs = 0; |
4814 | } | 4901 | } |
4815 | n = redir; | 4902 | n = redir; |
4816 | do { | 4903 | do { |
@@ -4861,7 +4948,7 @@ popredir(int drop) | |||
4861 | struct redirtab *rp; | 4948 | struct redirtab *rp; |
4862 | int i; | 4949 | int i; |
4863 | 4950 | ||
4864 | if (--nullredirs >= 0) | 4951 | if (--g_nullredirs >= 0) |
4865 | return; | 4952 | return; |
4866 | INT_OFF; | 4953 | INT_OFF; |
4867 | rp = redirlist; | 4954 | rp = redirlist; |
@@ -4880,7 +4967,7 @@ popredir(int drop) | |||
4880 | } | 4967 | } |
4881 | } | 4968 | } |
4882 | redirlist = rp->next; | 4969 | redirlist = rp->next; |
4883 | nullredirs = rp->nullredirs; | 4970 | g_nullredirs = rp->nullredirs; |
4884 | free(rp); | 4971 | free(rp); |
4885 | INT_ON; | 4972 | INT_ON; |
4886 | } | 4973 | } |
@@ -4896,7 +4983,7 @@ static void | |||
4896 | clearredir(int drop) | 4983 | clearredir(int drop) |
4897 | { | 4984 | { |
4898 | for (;;) { | 4985 | for (;;) { |
4899 | nullredirs = 0; | 4986 | g_nullredirs = 0; |
4900 | if (!redirlist) | 4987 | if (!redirlist) |
4901 | break; | 4988 | break; |
4902 | popredir(drop); | 4989 | popredir(drop); |
@@ -6458,7 +6545,6 @@ static void find_command(char *, struct cmdentry *, int, const char *); | |||
6458 | * would make the command name "hash" a misnomer. | 6545 | * would make the command name "hash" a misnomer. |
6459 | */ | 6546 | */ |
6460 | 6547 | ||
6461 | #define CMDTABLESIZE 31 /* should be prime */ | ||
6462 | #define ARB 1 /* actual size determined at run time */ | 6548 | #define ARB 1 /* actual size determined at run time */ |
6463 | 6549 | ||
6464 | struct tblentry { | 6550 | struct tblentry { |
@@ -6469,8 +6555,13 @@ struct tblentry { | |||
6469 | char cmdname[ARB]; /* name of command */ | 6555 | char cmdname[ARB]; /* name of command */ |
6470 | }; | 6556 | }; |
6471 | 6557 | ||
6472 | static struct tblentry *cmdtable[CMDTABLESIZE]; | 6558 | static struct tblentry **cmdtable; |
6473 | static int builtinloc = -1; /* index in path of %builtin, or -1 */ | 6559 | #define INIT_G_cmdtable() do { \ |
6560 | cmdtable = xzalloc(CMDTABLESIZE * sizeof(cmdtable[0])); \ | ||
6561 | } while (0) | ||
6562 | |||
6563 | static int builtinloc = -1; /* index in path of %builtin, or -1 */ | ||
6564 | |||
6474 | 6565 | ||
6475 | static void | 6566 | static void |
6476 | tryexec(char *cmd, char **argv, char **envp) | 6567 | tryexec(char *cmd, char **argv, char **envp) |
@@ -7840,7 +7931,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
7840 | savehandler = exception_handler; | 7931 | savehandler = exception_handler; |
7841 | exception_handler = &jmploc; | 7932 | exception_handler = &jmploc; |
7842 | localvars = NULL; | 7933 | localvars = NULL; |
7843 | shellparam.malloc = 0; | 7934 | shellparam.malloced = 0; |
7844 | func->count++; | 7935 | func->count++; |
7845 | funcnest++; | 7936 | funcnest++; |
7846 | INT_ON; | 7937 | INT_ON; |
@@ -7851,7 +7942,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) | |||
7851 | shellparam.optoff = -1; | 7942 | shellparam.optoff = -1; |
7852 | #endif | 7943 | #endif |
7853 | evaltree(&func->n, flags & EV_TESTED); | 7944 | evaltree(&func->n, flags & EV_TESTED); |
7854 | funcdone: | 7945 | funcdone: |
7855 | INT_OFF; | 7946 | INT_OFF; |
7856 | funcnest--; | 7947 | funcnest--; |
7857 | freefunc(func); | 7948 | freefunc(func); |
@@ -8979,7 +9070,7 @@ setparam(char **argv) | |||
8979 | } | 9070 | } |
8980 | *ap = NULL; | 9071 | *ap = NULL; |
8981 | freeparam(&shellparam); | 9072 | freeparam(&shellparam); |
8982 | shellparam.malloc = 1; | 9073 | shellparam.malloced = 1; |
8983 | shellparam.nparam = nparam; | 9074 | shellparam.nparam = nparam; |
8984 | shellparam.p = newparam; | 9075 | shellparam.p = newparam; |
8985 | #if ENABLE_ASH_GETOPTS | 9076 | #if ENABLE_ASH_GETOPTS |
@@ -9094,7 +9185,7 @@ shiftcmd(int argc, char **argv) | |||
9094 | INT_OFF; | 9185 | INT_OFF; |
9095 | shellparam.nparam -= n; | 9186 | shellparam.nparam -= n; |
9096 | for (ap1 = shellparam.p; --n >= 0; ap1++) { | 9187 | for (ap1 = shellparam.p; --n >= 0; ap1++) { |
9097 | if (shellparam.malloc) | 9188 | if (shellparam.malloced) |
9098 | free(*ap1); | 9189 | free(*ap1); |
9099 | } | 9190 | } |
9100 | ap2 = shellparam.p; | 9191 | ap2 = shellparam.p; |
@@ -10971,7 +11062,7 @@ dotcmd(int argc, char **argv) | |||
10971 | 11062 | ||
10972 | if (argc > 2) { | 11063 | if (argc > 2) { |
10973 | saveparam = shellparam; | 11064 | saveparam = shellparam; |
10974 | shellparam.malloc = 0; | 11065 | shellparam.malloced = 0; |
10975 | shellparam.nparam = argc - 2; | 11066 | shellparam.nparam = argc - 2; |
10976 | shellparam.p = argv + 2; | 11067 | shellparam.p = argv + 2; |
10977 | }; | 11068 | }; |
@@ -12741,7 +12832,7 @@ procargs(int argc, char **argv) | |||
12741 | shellparam.optind = 1; | 12832 | shellparam.optind = 1; |
12742 | shellparam.optoff = -1; | 12833 | shellparam.optoff = -1; |
12743 | #endif | 12834 | #endif |
12744 | /* assert(shellparam.malloc == 0 && shellparam.nparam == 0); */ | 12835 | /* assert(shellparam.malloced == 0 && shellparam.nparam == 0); */ |
12745 | while (*xargv) { | 12836 | while (*xargv) { |
12746 | shellparam.nparam++; | 12837 | shellparam.nparam++; |
12747 | xargv++; | 12838 | xargv++; |
@@ -12805,6 +12896,13 @@ int ash_main(int argc, char **argv) | |||
12805 | struct jmploc jmploc; | 12896 | struct jmploc jmploc; |
12806 | struct stackmark smark; | 12897 | struct stackmark smark; |
12807 | 12898 | ||
12899 | /* Initialize global data */ | ||
12900 | INIT_G_misc(); | ||
12901 | INIT_G_memstack(); | ||
12902 | INIT_G_var(); | ||
12903 | INIT_G_alias(); | ||
12904 | INIT_G_cmdtable(); | ||
12905 | |||
12808 | #if PROFILE | 12906 | #if PROFILE |
12809 | monitor(4, etext, profile_buf, sizeof(profile_buf), 50); | 12907 | monitor(4, etext, profile_buf, sizeof(profile_buf), 50); |
12810 | #endif | 12908 | #endif |