Add bjdwp tool to Barry project.
[barry/progweb.git] / bjdwp / src / server.cc
blobcb08984d4884bb6ee05e125147792449d0afd21e
1 #include <stdlib.h>
2 #include <stdint.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <pthread.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <netinet/in.h>
10 #include <arpa/inet.h>
11 #include <netdb.h>
13 #include <algorithm>
14 #include <functional>
15 #include <vector>
17 #include <barry/endian.h>
18 #include <barry/barry.h>
20 #include "message.h"
21 #include "handler.h"
22 #include "server.h"
23 #include "protocol.h"
24 #include "data.h"
27 using namespace std;
28 using namespace Barry;
29 using namespace JDG;
32 namespace JDWP {
34 static void * acceptWrapper(void *data);
37 JDWServer::JDWServer(const char *address, int port)
39 sockfd = -1;
40 handler = NULL;
42 this->address = strdup(address);
43 this->port = port;
44 this->printConsoleMessage = NULL;
46 searchDebugFile(debugFileList);
50 JDWServer::~JDWServer()
52 stop();
54 free(address);
58 void JDWServer::setDevice(Barry::Mode::JVMDebug *device)
60 jvmdebug = device;
64 void JDWServer::setPasswordDevice(string password)
66 this->password = password;
70 void JDWServer::setConsoleCallback(void (*callback)(string message))
72 printConsoleMessage = callback;
76 bool JDWServer::start()
78 int rc;
80 struct hostent *hp;
81 struct sockaddr_in sad;
84 memset((char *) &sad, '\0', sizeof(struct sockaddr_in));
86 if (address == NULL)
87 sad.sin_addr.s_addr = INADDR_ANY;
88 else {
89 sad.sin_addr.s_addr = inet_addr(address);
91 if (sad.sin_addr.s_addr == INADDR_NONE) {
92 hp = gethostbyname(address);
94 if (hp == NULL) {
95 // TODO
96 // throw Exception...
97 exit(-1);
100 memcpy((char*) &sad.sin_addr, (char*) hp->h_addr, (size_t) hp->h_length);
104 sad.sin_family = AF_INET;
105 sad.sin_port = htons((short) (port & 0xFFFF));
107 // Open socket
108 sockfd = socket(sad.sin_family, SOCK_STREAM, 0);
110 if (sockfd < 0) {
111 // TODO
112 // Throw Exception
113 exit(-1);
116 // Bind
117 rc = bind(sockfd, (struct sockaddr *) &sad, sizeof(sad));
119 if (rc < 0) {
120 close(sockfd);
121 sockfd = -1;
123 // TODO
124 // Throw Exception
125 exit(-1);
128 // Listen
129 if (listen(sockfd, SOMAXCONN) < 0) {
130 close(sockfd);
131 sockfd = -1;
133 // TODO
134 // Throw Exception
135 exit(-1);
138 handler = new JDWHandler(sockfd, acceptWrapper, (void*) this);
140 return true;
144 static void * acceptWrapper(void *data) {
145 JDWServer *s;
147 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
149 s = (JDWServer *) data;
151 while (1) {
152 s->acceptConnection();
154 s->attachToDevice();
156 if (s->hello()) {
157 s->run();
159 s->detachFromDevice();
163 return NULL;
167 void JDWServer::acceptConnection() {
168 size_t addrlen;
170 struct sockaddr *sa;
171 struct sockaddr_in addr;
173 sa = (struct sockaddr*) &addr;
175 addrlen = sizeof(addr);
177 fd = accept(sockfd, sa, &addrlen);
179 fcntl(fd, F_SETFL, O_NONBLOCK);
181 if (fd < 0)
182 return;
186 void JDWServer::attachToDevice() {
187 bool ret;
189 targetrunning = false;
191 jvmdebug->Open(password.c_str());
192 jvmdebug->Attach();
194 jvmdebug->Unknown01();
195 jvmdebug->Unknown02();
196 jvmdebug->Unknown03();
197 jvmdebug->Unknown04();
198 jvmdebug->Unknown05();
200 jvmdebug->GetModulesList(modulesList);
201 cout << modulesList;
203 // Check debug info for each modules
204 vector<JVMModulesEntry>::iterator b = modulesList.begin();
205 for ( ; b != modulesList.end(); b++) {
206 JDGCodInfo codInfo;
208 JVMModulesEntry entry = *b;
210 ret = loadDebugInfo(debugFileList, entry.UniqueID, entry.Name, codInfo);
212 if (ret == true) {
213 appList[entry.UniqueID].load(codInfo);
215 else {
216 cout << "No debug information found for '" << entry.Name;
217 cout << "' (" << hex << setfill('0') << setw(8) << entry.UniqueID << ")." << endl;
223 void JDWServer::detachFromDevice() {
224 jvmdebug->Detach();
225 jvmdebug->Close();
229 #define JDWP_HELLO_STRING "JDWP-Handshake"
233 bool JDWServer::hello() {
234 bool ret;
236 Barry::Data response;
238 const size_t len = strlen(JDWP_HELLO_STRING);
240 JDWMessage msg(fd);
242 do {
243 ret = msg.Receive(response);
245 while (!ret);
247 int size = response.GetSize();
248 char *str = (char *) response.GetBuffer();
250 if (size != len)
251 return false;
253 if (!strncmp(str, JDWP_HELLO_STRING, len)) {
254 Data command(JDWP_HELLO_STRING, len);
256 msg.Send(command);
258 return true;
261 return false;
265 void JDWServer::run() {
266 string str;
267 JDWMessage msg(fd);
269 Barry::Data command;
271 MAKE_JDWPPACKET(rpack, command);
273 loop = true;
275 while (loop) {
276 if (targetrunning) {
277 // Read JDWP message from device
278 int value = jvmdebug->GetConsoleMessage(str);
280 if (value < 0) {
281 bool ret;
282 int status;
284 ret = jvmdebug->GetStatus(status);
286 while (!ret) {
287 // Read JDB message from host
288 msg.Receive(command);
290 if (command.GetSize() > 0) {
291 // Convert to packet
292 rpack = (const Protocol::Packet *) command.GetData();
294 if (command.GetSize() != be_btohl(rpack->length)) {
295 cout << "Packet size error !!!" << endl;
297 // TODO : add throw exception
299 continue;
302 CommandsetProcess(command);
304 break;
306 else
307 ret = jvmdebug->WaitStatus(status);
310 else {
311 if (printConsoleMessage != NULL)
312 printConsoleMessage(str);
315 else {
316 // Read JDB message from host
317 msg.Receive(command);
319 if (command.GetSize() > 0) {
320 // Convert to packet
321 rpack = (const Protocol::Packet *) command.GetData();
323 if (command.GetSize() != be_btohl(rpack->length)) {
324 cout << "Packet size error !!!" << endl;
326 // TODO : add throw exception
328 continue;
331 CommandsetProcess(command);
334 usleep(50);
340 bool JDWServer::stop() {
341 if (handler) {
342 handler->dispose();
343 handler = 0;
346 if (sockfd >= 0)
347 close(sockfd);
349 sockfd = -1;
351 return true;
355 void JDWServer::CommandsetProcess(Data &cmd) {
356 MAKE_JDWPPACKET(rpack, cmd);
358 switch (rpack->u.command.commandset) {
359 case JDWP_CMDSET_VIRTUALMACHINE:
360 CommandsetVirtualMachineProcess(cmd);
361 break;
363 case JDWP_CMDSET_REFERECENTYPE:
364 break;
366 case JDWP_CMDSET_CLASSTYPE:
367 break;
369 case JDWP_CMDSET_ARRAYTYPE:
370 break;
372 case JDWP_CMDSET_INTERFACETYPE:
373 break;
375 case JDWP_CMDSET_METHOD:
376 break;
378 case JDWP_CMDSET_FIELD:
379 break;
381 case JDWP_CMDSET_OBJECTREFERENCE:
382 break;
384 case JDWP_CMDSET_STRINGREFERENCE:
385 break;
387 case JDWP_CMDSET_THREADREFERENCE:
388 break;
390 case JDWP_CMDSET_THREADGROUPREFERENCE:
391 break;
393 case JDWP_CMDSET_ARRAYREFERENCE:
394 break;
396 case JDWP_CMDSET_CLASSLOADERREFERENCE:
397 break;
399 case JDWP_CMDSET_EVENTREQUEST:
400 CommandsetEventRequestProcess(cmd);
401 break;
403 case JDWP_CMDSET_STACKFRAME:
404 break;
406 case JDWP_CMDSET_CLASSOBJECTREFERENCE:
407 break;
409 case JDWP_CMDSET_EVENT:
410 break;
412 default:
413 // TODO : add exception (or alert)
414 cout << "Commandset unknown !!!" << endl;
419 void JDWServer::CommandsetVirtualMachineProcess(Data &cmd) {
420 JDWMessage msg(fd);
422 MAKE_JDWPPACKET(rpack, cmd);
424 switch (rpack->u.command.command) {
425 case JDWP_CMD_VERSION:
426 CommandVersion(cmd);
427 break;
429 case JDWP_CMD_ALLCLASSES:
430 CommandAllClasses(cmd);
431 break;
433 case JDWP_CMD_ALLTHREADS:
434 CommandAllThreads(cmd);
435 break;
437 case JDWP_CMD_DISPOSE:
438 loop = false;
439 targetrunning = false;
440 close(fd);
441 break;
443 case JDWP_CMD_IDSIZES:
444 CommandIdSizes(cmd);
445 break;
447 case JDWP_CMD_SUSPEND:
448 CommandSuspend(cmd);
449 targetrunning = false;
450 break;
452 case JDWP_CMD_RESUME:
453 CommandResume(cmd);
454 targetrunning = true;
455 break;
457 case JDWP_CMD_CLASSPATHS:
458 CommandClassPaths(cmd);
459 break;
464 void JDWServer::CommandsetEventRequestProcess(Data &cmd) {
465 JDWMessage msg(fd);
467 MAKE_JDWPPACKET(rpack, cmd);
469 switch (rpack->u.command.command) {
470 case JDWP_CMD_SET:
471 CommandSet(cmd);
472 break;
477 void JDWServer::CommandVersion(Data &cmd) {
478 JDWMessage msg(fd);
480 // Build packet data
481 Data response;
483 size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
485 AddDataString(response, offset, string("RIM JVM"));
486 AddDataInt(response, offset, be_htobl(1));
487 AddDataInt(response, offset, be_htobl(4));
488 AddDataString(response, offset, string("1.4"));
489 AddDataString(response, offset, string("RIM JVM"));
491 response.ReleaseBuffer(offset);
494 size_t total_size = response.GetSize();
496 // Fill in the header values
497 MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size));
498 Protocol::Packet &packet = *cpack;
501 MAKE_JDWPPACKET(rpack, cmd);
503 packet.length = be_htobl(total_size);
504 packet.id = rpack->id;
505 packet.flags = 0x80;
506 packet.u.response.errorcode = be_htobs(0);
508 response.ReleaseBuffer(total_size);
509 msg.Send(response);
513 //struct ClassesFormat {
514 // uint8_t refTypeTag;
515 // uint32_t typeID;
516 // const char *signature;
517 // uint32_t status;
518 //};
519 // struct ClassesFormat myClasses[] = {
520 // { 0x01, 0x01, "Lcom/rim/resources/net_rim_rimsecuridlibRIMResources;", 0x04 },
521 // { 0x01, 0x02, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimDatabaseFullException;", 0x04 },
522 // { 0x01, 0x03, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimDecryptFailException;", 0x04 },
523 // { 0x01, 0x04, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimDuplicateNameException;", 0x04 },
524 // { 0x01, 0x05, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimDuplicateTokenException;", 0x04 },
525 // { 0x01, 0x06, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimInvalidParamException;", 0x04 },
526 // { 0x01, 0x07, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimSecurIDLib;", 0x04 },
527 // { 0x01, 0x08, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimWrongDeviceIDException;", 0x04 },
528 // { 0x01, 0x09, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimWrongFormFactorException;", 0x04 },
529 // { 0xFF }
530 // };
533 void JDWServer::CommandAllClasses(Data &cmd) {
534 int index;
536 JDWMessage msg(fd);
538 // Build packet data
539 Data response;
541 size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
543 // Count and index the class (start to '1')
544 index = 1;
545 map<uint32_t, JDWAppInfo>::iterator it;
547 for (it = appList.begin(); it != appList.end(); it++) {
548 JDWAppInfo *appInfo = &(it->second);
549 JDGClassList *list = &(appInfo->classList);
551 vector<JDGClassEntry>::iterator b;
553 for (b = list->begin(); b != list->end(); b++) {
554 // FIXME
555 // I don't from class field, we have to filter the class view by JDB
556 if (b->type != 0x824)
557 continue;
559 b->index = index++;
563 // Add '9' for the static class
564 AddDataInt(response, offset, be_htobl(index + 9 - 1));
566 // Then, write the list of known class
567 for (it = appList.begin(); it != appList.end(); it++) {
568 JDWAppInfo *appInfo = &(it->second);
569 JDGClassList *list = &(appInfo->classList);
571 vector<JDGClassEntry>::iterator b;
573 for (b = list->begin(); b != list->end(); b++) {
574 // FIXME
575 // I don't from class field, we have to filter the class view by JDB
576 if (b->type != 0x824)
577 continue;
579 string str = b->getFullClassName();
581 str = "L" + str + ";";
582 // replace_if(str.begin(), str.end(), bind2nd(equal_to<char>(),'.'), '/');
583 cout << hex << b->index << "-" << str << "-" << endl;
584 AddDataByte(response, offset, 0x01);
585 AddDataInt(response, offset, b->index);
586 AddDataString(response, offset, str);
587 AddDataInt(response, offset, be_htobl(0x04));
591 // Then, write the default class (like RIM)
592 AddDataByte(response, offset, 0x01);
593 AddDataInt(response, offset, index++);
594 AddDataString(response, offset, "Lcom/rim/resources/net_rim_rimsecuridlibRIMResources;");
595 AddDataInt(response, offset, be_htobl(0x04));
597 AddDataByte(response, offset, 0x01);
598 AddDataInt(response, offset, index++);
599 AddDataString(response, offset, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimDatabaseFullException;");
600 AddDataInt(response, offset, be_htobl(0x04));
602 AddDataByte(response, offset, 0x01);
603 AddDataInt(response, offset, index++);
604 AddDataString(response, offset, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimDecryptFailException;");
605 AddDataInt(response, offset, be_htobl(0x04));
607 AddDataByte(response, offset, 0x01);
608 AddDataInt(response, offset, index++);
609 AddDataString(response, offset, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimDuplicateNameException;");
610 AddDataInt(response, offset, be_htobl(0x04));
612 AddDataByte(response, offset, 0x01);
613 AddDataInt(response, offset, index++);
614 AddDataString(response, offset, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimDuplicateTokenException;");
615 AddDataInt(response, offset, be_htobl(0x04));
617 AddDataByte(response, offset, 0x01);
618 AddDataInt(response, offset, index++);
619 AddDataString(response, offset, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimInvalidParamException;");
620 AddDataInt(response, offset, be_htobl(0x04));
622 AddDataByte(response, offset, 0x01);
623 AddDataInt(response, offset, index++);
624 AddDataString(response, offset, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimSecurIDLib;");
625 AddDataInt(response, offset, be_htobl(0x04));
627 AddDataByte(response, offset, 0x01);
628 AddDataInt(response, offset, index++);
629 AddDataString(response, offset, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimWrongDeviceIDException;");
630 AddDataInt(response, offset, be_htobl(0x04));
632 AddDataByte(response, offset, 0x01);
633 AddDataInt(response, offset, index++);
634 AddDataString(response, offset, "Lnet/rim/device/cldc/impl/softtoken/rimsecuridlib/RimWrongFormFactorException;");
635 AddDataInt(response, offset, be_htobl(0x04));
638 response.ReleaseBuffer(offset);
641 size_t total_size = response.GetSize();
643 // Fill in the header values
644 MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size));
645 Protocol::Packet &packet = *cpack;
648 MAKE_JDWPPACKET(rpack, cmd);
650 packet.length = be_htobl(total_size);
651 packet.id = rpack->id;
652 packet.flags = 0x80;
653 packet.u.response.errorcode = be_htobs(0);
655 response.ReleaseBuffer(total_size);
656 msg.Send(response);
660 void JDWServer::CommandAllThreads(Data &cmd) {
661 JDWMessage msg(fd);
663 // Get threads list from device
664 JVMThreadsList list;
665 jvmdebug->GetThreadsList(list);
666 cout << list;
668 // Build packet data
669 Data response;
671 size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
673 // Indicate the number of element
674 AddDataInt(response, offset, be_htobl(list.size()));
676 // Send all threads ID
677 vector<JVMThreadsEntry>::iterator b = list.begin();
678 for( ; b != list.end(); b++ ) {
679 JVMThreadsEntry entry = *b;
681 AddDataInt(response, offset, be_htobl(entry.Id));
684 response.ReleaseBuffer(offset);
687 size_t total_size = response.GetSize();
689 // Fill in the header values
690 MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size));
691 Protocol::Packet &packet = *cpack;
694 MAKE_JDWPPACKET(rpack, cmd);
696 packet.length = be_htobl(total_size);
697 packet.id = rpack->id;
698 packet.flags = 0x80;
699 packet.u.response.errorcode = be_htobs(0);
701 response.ReleaseBuffer(total_size);
702 msg.Send(response);
706 void JDWServer::CommandIdSizes(Data &cmd) {
707 JDWMessage msg(fd);
709 MAKE_JDWPPACKET(rpack, cmd);
711 size_t size;
713 Protocol::Packet packet;
715 size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE
716 + JDWP_PACKETVIRTUALMACHINEIDSIZES_DATA_SIZE;
718 packet.length = be_htobl(size);
719 packet.id = rpack->id;
720 packet.flags = 0x80;
721 packet.u.response.errorcode = be_htobs(0);
722 packet.u.response.u.virtualMachine.u.IDSizes.fieldIDSize = be_htobl(0x04);
723 packet.u.response.u.virtualMachine.u.IDSizes.methodIDSize = be_htobl(0x04);
724 packet.u.response.u.virtualMachine.u.IDSizes.objectIDSize = be_htobl(0x04);
725 packet.u.response.u.virtualMachine.u.IDSizes.referenceTypeIDSize = be_htobl(0x04);
726 packet.u.response.u.virtualMachine.u.IDSizes.frameIDSize = be_htobl(0x04);
728 Data response(&packet, size);
730 msg.Send(response);
734 void JDWServer::CommandSuspend(Data &cmd) {
735 JDWMessage msg(fd);
738 // Suspend device
739 jvmdebug->Stop();
741 // Notify debugger
742 MAKE_JDWPPACKET(rpack, cmd);
744 size_t size;
746 Protocol::Packet packet;
748 size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
750 packet.length = be_htobl(size);
751 packet.id = rpack->id;
752 packet.flags = 0x80;
753 packet.u.response.errorcode = be_htobs(0);
755 Data response(&packet, size);
757 msg.Send(response);
761 void JDWServer::CommandResume(Data &cmd) {
762 JDWMessage msg(fd);
765 // Resume device
766 jvmdebug->Unknown06();
767 jvmdebug->Unknown07();
768 jvmdebug->Unknown08();
769 jvmdebug->Unknown09();
770 jvmdebug->Unknown10();
771 jvmdebug->Go();
773 // Notify debugger
774 MAKE_JDWPPACKET(rpack, cmd);
776 size_t size;
778 Protocol::Packet packet;
780 size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
782 packet.length = be_htobl(size);
783 packet.id = rpack->id;
784 packet.flags = 0x80;
785 packet.u.response.errorcode = be_htobs(0);
787 Data response(&packet, size);
789 msg.Send(response);
793 void JDWServer::CommandClassPaths(Data &cmd) {
794 JDWMessage msg(fd);
796 // Build packet data
797 Data response;
799 size_t offset = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE;
801 AddDataString(response, offset, string(""));
802 AddDataInt(response, offset, be_htobl(0));
803 AddDataInt(response, offset, be_htobl(0));
805 response.ReleaseBuffer(offset);
808 size_t total_size = response.GetSize();
810 // Fill in the header values
811 MAKE_JDWPPACKETPTR_BUF(cpack, response.GetBuffer(total_size));
812 Protocol::Packet &packet = *cpack;
815 MAKE_JDWPPACKET(rpack, cmd);
817 packet.length = be_htobl(total_size);
818 packet.id = rpack->id;
819 packet.flags = 0x80;
820 packet.u.response.errorcode = be_htobs(0);
822 response.ReleaseBuffer(total_size);
823 msg.Send(response);
828 void JDWServer::CommandSet(Data &cmd) {
829 static int value = 2;
831 JDWMessage msg(fd);
833 MAKE_JDWPPACKET(rpack, cmd);
835 size_t size;
837 Protocol::Packet packet;
839 size = JDWP_PACKET_HEADER_SIZE + JDWP_RESPONSE_HEADER_SIZE + sizeof(uint32_t);
841 packet.length = be_htobl(size);
842 packet.id = rpack->id;
843 packet.flags = 0x80;
844 packet.u.response.errorcode = be_htobs(0);
845 packet.u.response.u.value = be_htobl(value);
847 Data response(&packet, size);
849 msg.Send(response);
851 value++;
855 } // namespace JDWP