]>
git.saurik.com Git - cycript.git/blob - Console.cpp
f83c3a25118cf8b8764a77f4d0fbd9dba1d20f9a
   1 /* Cycript - Remove Execution Server and Disassembler 
   2  * Copyright (C) 2009  Jay Freeman (saurik) 
   5 /* Modified BSD License {{{ */ 
   7  *        Redistribution and use in source and binary 
   8  * forms, with or without modification, are permitted 
   9  * provided that the following conditions are met: 
  11  * 1. Redistributions of source code must retain the 
  12  *    above copyright notice, this list of conditions 
  13  *    and the following disclaimer. 
  14  * 2. Redistributions in binary form must reproduce the 
  15  *    above copyright notice, this list of conditions 
  16  *    and the following disclaimer in the documentation 
  17  *    and/or other materials provided with the 
  19  * 3. The name of the author may not be used to endorse 
  20  *    or promote products derived from this software 
  21  *    without specific prior written permission. 
  23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' 
  24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
  25  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
  26  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  27  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE 
  28  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
  29  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
  30  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
  31  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
  33  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
  34  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
  35  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
  36  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  42 #include <substrate.h> 
  43 #include "cycript.hpp" 
  50 #include <readline/readline.h> 
  51 #include <readline/history.h> 
  58 #include <sys/types.h> 
  62 #include "Cycript.tab.hh" 
  64 #include <sys/types.h> 
  65 #include <sys/socket.h> 
  66 #include <netinet/in.h> 
  69 static volatile enum { 
  77 static jmp_buf ctrlc_
; 
  79 static void sigint(int) { 
  98 void Setup(cy::parser 
&parser
) { 
 101         parser
.set_debug_level(1); 
 105 void Run(int socket
, const char *data
, size_t size
, FILE *fout 
= NULL
, bool expand 
= false) { 
 111         json 
= CYExecute(pool
, data
); 
 117         CYSendAll(socket
, &size
, sizeof(size
)); 
 118         CYSendAll(socket
, data
, size
); 
 120         CYRecvAll(socket
, &size
, sizeof(size
)); 
 121         if (size 
== _not(size_t)) 
 124             char *temp(new(pool
) char[size 
+ 1]); 
 125             CYRecvAll(socket
, temp
, size
); 
 132     if (json 
!= NULL 
&& fout 
!= NULL
) { 
 133         if (!expand 
|| json
[0] != '"' && json
[0] != '\'') 
 135         else for (size_t i(0); i 
!= size
; ++i
) 
 137                 fputc(json
[i
], fout
); 
 138             else switch(json
[++i
]) { 
 139                 case '\0': goto done
; 
 140                 case '\\': fputc('\\', fout
); break; 
 141                 case '\'': fputc('\'', fout
); break; 
 142                 case '"': fputc('"', fout
); break; 
 143                 case 'b': fputc('\b', fout
); break; 
 144                 case 'f': fputc('\f', fout
); break; 
 145                 case 'n': fputc('\n', fout
); break; 
 146                 case 'r': fputc('\r', fout
); break; 
 147                 case 't': fputc('\t', fout
); break; 
 148                 case 'v': fputc('\v', fout
); break; 
 149                 default: fputc('\\', fout
); --i
; break; 
 158 void Run(int socket
, std::string 
&code
, FILE *fout 
= NULL
, bool expand 
= false) { 
 159     Run(socket
, code
.c_str(), code
.size(), fout
, expand
); 
 162 static void Console(int socket
) { 
 169     rl_bind_key('\t', rl_insert
); 
 171     struct sigaction action
; 
 172     sigemptyset(&action
.sa_mask
); 
 173     action
.sa_handler 
= &sigint
; 
 175     sigaction(SIGINT
, &action
, NULL
); 
 179         std::vector
<std::string
> lines
; 
 182         const char *prompt("cy# "); 
 184         if (setjmp(ctrlc_
) != 0) { 
 193         char *line(readline(prompt
)); 
 200             if (line
[0] == '?') { 
 201                 std::string 
data(line 
+ 1); 
 202                 if (data 
== "bypass") { 
 204                     fprintf(fout
, "bypass == %s\n", bypass 
? "true" : "false"); 
 206                 } else if (data 
== "debug") { 
 208                     fprintf(fout
, "debug == %s\n", debug 
? "true" : "false"); 
 210                 } else if (data 
== "expand") { 
 212                     fprintf(fout
, "expand == %s\n", expand 
? "true" : "false"); 
 221         for (char *state
, *token(apr_strtok(line
, "\n", &state
)); token 
!= NULL
; token 
= apr_strtok(NULL
, "\n", &state
)) 
 222             lines
.push_back(token
); 
 231             cy::parser 
parser(driver
); 
 234             driver
.data_ 
= command
.c_str(); 
 235             driver
.size_ 
= command
.size(); 
 237             if (parser
.parse() != 0 || !driver
.errors_
.empty()) { 
 238                 for (CYDriver::Errors::const_iterator 
error(driver
.errors_
.begin()); error 
!= driver
.errors_
.end(); ++error
) { 
 239                     cy::position 
begin(error
->location_
.begin
); 
 240                     if (begin
.line 
!= lines
.size() || begin
.column 
- 1 != lines
.back().size()) { 
 241                         cy::position 
end(error
->location_
.end
); 
 243                         if (begin
.line 
!= lines
.size()) { 
 245                             std::cerr 
<< lines
[begin
.line 
- 1] << std::endl
; 
 249                         for (size_t i(0); i 
!= begin
.column 
- 1; ++i
) 
 251                         if (begin
.line 
!= end
.line 
|| begin
.column 
== end
.column
) 
 253                         else for (size_t i(0), e(end
.column 
- begin
.column
); i 
!= e
; ++i
) 
 255                         std::cerr 
<< std::endl
; 
 258                         std::cerr 
<< error
->message_ 
<< std::endl
; 
 260                         add_history(command
.c_str()); 
 265                 driver
.errors_
.clear(); 
 272             if (driver
.source_ 
== NULL
) 
 278                 std::ostringstream str
; 
 279                 driver
.source_
->Show(str
); 
 284         add_history(command
.c_str()); 
 287             std::cout 
<< code 
<< std::endl
; 
 289         Run(socket
, code
, fout
, expand
); 
 296 static void *Map(const char *path
, size_t *psize
) { 
 298     _syscall(fd 
= open(path
, O_RDONLY
)); 
 301     _syscall(fstat(fd
, &stat
)); 
 302     size_t size(stat
.st_size
); 
 307     _syscall(base 
= mmap(NULL
, size
, PROT_READ
, MAP_SHARED
, fd
, 0)); 
 313 int main(int argc
, char *argv
[]) { 
 314     bool tty(isatty(STDIN_FILENO
)); 
 315     pid_t 
pid(_not(pid_t
)); 
 318     for (;;) switch (getopt(argc
, argv
, "cg:p:")) { 
 322             fprintf(stderr
, "usage: cycript [-c] [-p <pid>] [<script> [<arg>...]]\n"); 
 332             else if (strcmp(optarg
, "bison") == 0) 
 336                 fprintf(stderr
, "invalid name for -g\n"); 
 342             size_t size(strlen(optarg
)); 
 344             pid 
= strtoul(optarg
, &end
, 0); 
 345             if (optarg 
+ size 
!= end
) { 
 346                 fprintf(stderr
, "invalid pid for -p\n"); 
 354     if (pid 
!= _not(pid_t
) && optind 
< argc 
- 1) { 
 355         fprintf(stderr
, "-p cannot set argv\n"); 
 359     if (pid 
!= _not(pid_t
) && compile
) { 
 360         fprintf(stderr
, "-p conflicts with -c\n"); 
 367         // XXX: const_cast?! wtf gcc :( 
 368         CYSetArgs(argc 
- optind 
- 1, const_cast<const char **>(argv 
+ optind 
+ 1)); 
 369         script 
= argv
[optind
]; 
 370         if (strcmp(script
, "-") == 0) 
 374     if (script 
== NULL 
&& !tty 
&& pid 
!= _not(pid_t
)) { 
 375         fprintf(stderr
, "non-terminal attaching to remove console\n"); 
 381     if (pid 
== _not(pid_t
)) 
 384         socket 
= _syscall(::socket(PF_UNIX
, SOCK_STREAM
, 0)); 
 386         struct sockaddr_un address
; 
 387         memset(&address
, 0, sizeof(address
)); 
 388         address
.sun_family 
= AF_UNIX
; 
 389         sprintf(address
.sun_path
, "/tmp/.s.cy.%u", pid
); 
 391         _syscall(connect(socket
, reinterpret_cast<sockaddr 
*>(&address
), SUN_LEN(&address
))); 
 394     if (script 
== NULL 
&& tty
) 
 397         CYDriver 
driver(script 
?: "<stdin>"); 
 398         cy::parser 
parser(driver
); 
 403         if (script 
== NULL
) { 
 407             driver
.file_ 
= stdin
; 
 410             start 
= reinterpret_cast<char *>(Map(script
, &size
)); 
 413             if (size 
>= 2 && start
[0] == '#' && start
[1] == '!') { 
 416                 if (void *line 
= memchr(start
, '\n', end 
- start
)) 
 417                     start 
= reinterpret_cast<char *>(line
); 
 422             driver
.data_ 
= start
; 
 423             driver
.size_ 
= end 
- start
; 
 426         if (parser
.parse() != 0 || !driver
.errors_
.empty()) { 
 427             for (CYDriver::Errors::const_iterator 
i(driver
.errors_
.begin()); i 
!= driver
.errors_
.end(); ++i
) 
 428                 std::cerr 
<< i
->location_
.begin 
<< ": " << i
->message_ 
<< std::endl
; 
 429         } else if (driver
.source_ 
!= NULL
) 
 431                 Run(socket
, start
, end 
- start
, stdout
); 
 433                 std::ostringstream str
; 
 434                 driver
.source_
->Show(str
); 
 435                 std::string 
code(str
.str());