PageRenderTime 53ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/archive/lkcdutils/qlcrash/qlcrash/qlcrashdoc.cpp

#
C++ | 2046 lines | 1640 code | 290 blank | 116 comment | 434 complexity | 1434c034dd4e44dfaa73a0cef20f8de6 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, LGPL-2.1, LGPL-2.0
  1. /*-*-c++-*-
  2. * $Id: qlcrashdoc.cpp 1053 2004-06-25 08:58:20Z holzheu $
  3. *
  4. * This file is part of qlcrash, a GUI for the dump-analysis tool lcrash.
  5. *
  6. * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
  7. *
  8. * Authors:
  9. * Michael Geselbracht (let@users.sourceforge.net)
  10. * Fritz Elfert (elfert@de.ibm.com)
  11. * Michael Holzheu (holzheu@de.ibm.com)
  12. *
  13. * This program is free software; you can redistribute it and/or modify
  14. * it under the terms of the GNU Lesser Public License as published by
  15. * the Free Software Foundation; either version 2.1 of the License, or
  16. * (at your option) any later version. See the file COPYING for more
  17. * information.
  18. */
  19. #include "qlcrashdoc.h"
  20. #include "parser.h"
  21. #include "cchildmanager.h"
  22. #include "cconfigmanager.h"
  23. #include "structviewitem.h"
  24. #include "crashtypes.h"
  25. #include "clistview.h"
  26. #include "cparseview.h"
  27. #include <qapplication.h>
  28. #include <qmessagebox.h>
  29. #include <qstringlist.h>
  30. #include <qtimer.h>
  31. #include <qcache.h>
  32. #include <qstring.h>
  33. #include <qregexp.h>
  34. #ifndef WIN32
  35. # ifndef _GNU_SOURCE
  36. # define _GNU_SOURCE
  37. # endif
  38. #endif
  39. #include <assert.h>
  40. #include <ctype.h>
  41. #include <stdlib.h>
  42. #ifndef WIN32
  43. #include <stdint.h>
  44. #ifdef USE_REGEX
  45. #include <regex.h>
  46. #endif
  47. #else
  48. #ifdef USE_REGEX
  49. #include <hsregex.h>
  50. #endif
  51. #endif
  52. #include <signal.h>
  53. #include <iostream>
  54. #include "avl.h"
  55. // max. number of walk iterations
  56. #define WALKMAX 500
  57. using namespace std;
  58. int hexCharToInt(unsigned char ch)
  59. {
  60. int retval = ch - '0';
  61. if (retval > 9) {
  62. retval = ch - 'A' + 10;
  63. }
  64. if (retval > 15) {
  65. retval = ch - 'a' + 10;
  66. }
  67. return retval;
  68. }
  69. void removeTypeInfo(QString &result)
  70. {
  71. int rc=result.findRev(')', -1);
  72. if(rc != -1){
  73. // since lkcdutils 4.2 the output of
  74. // print ((task_struct*)0x..)->next_task
  75. // is '(task_struct *) 0x... >>'
  76. // we must get rid of the leading
  77. // type description
  78. result = result.mid(rc + 1);
  79. }
  80. }
  81. void dereferencePointerType(QString &result)
  82. {
  83. int rc=result.findRev('*', -1);
  84. if(rc != -1){
  85. result = result.left(rc);
  86. }
  87. }
  88. QLcrashDoc::QLcrashDoc(CConfigManager* cm, QObject* parent, const char* name)
  89. : QObject(parent, name)
  90. , oConfigManager(cm)
  91. , oGraph(false)
  92. , oWaitForInit(true)
  93. , oQuitAfterChildExit(false)
  94. , lcrashIsReady(false)
  95. , oS390dbf(-1)
  96. , oTargetEndian(unknown)
  97. , oTargetWordSize(-1)
  98. {
  99. oParser = new CParser(this);
  100. oChildManager = new CChildManager(this);
  101. oDumpCache = new QCache<unsigned char>(100, 131);
  102. connect(oChildManager, SIGNAL(sigChildDied()), SLOT(slotChildDied()));
  103. connect(oChildManager, SIGNAL(sigStdout(QString)), SLOT(slotStdoutFromChild(QString)));
  104. connect(oChildManager, SIGNAL(sigStderr(QString)), SLOT(slotStderrFromChild(QString)));
  105. connect(oChildManager, SIGNAL(sigBusy(bool)), SIGNAL(sigBusy(bool)));
  106. connect(this, SIGNAL(sigSetup()), oChildManager, SLOT(slotSetup()));
  107. oInitialTimer = new QTimer(this);
  108. connect(oInitialTimer, SIGNAL(timeout()), SLOT(slotInitialTimeout()));
  109. oInitialTimer->start(1000, true);
  110. }
  111. QLcrashDoc::~QLcrashDoc()
  112. {
  113. }
  114. void
  115. QLcrashDoc::slotSetup() {
  116. emit sigSetup();
  117. }
  118. void
  119. QLcrashDoc::slotFromConsole(CNConsole* con, QString str)
  120. {
  121. // don't accept user input until initialization of lcrash is complete
  122. if (oWaitForInit) {
  123. return;
  124. }
  125. str = str.stripWhiteSpace();
  126. if (str.isEmpty()) {
  127. emit sigToConsole(con, /*QString("\n") +*/ CMD_PROMPT);
  128. return;
  129. }
  130. if (str == "quit" || str == "q!" || str == "q") {
  131. emit sigExit(true);
  132. return;
  133. }
  134. if (str.left(2) == "vi") {
  135. printErr(tr("Editing of sial functions not supported from within qlcrash"));
  136. return;
  137. }
  138. if (str.left(5) == "graph") {
  139. oGraph = true;
  140. str = str.mid(5).stripWhiteSpace();
  141. }
  142. if (str.left(5) == "print") {
  143. QString tmp = str.mid(5).stripWhiteSpace();
  144. if ((tmp.left(2) != "-x") &&
  145. (tmp.left(2) != "-d") &&
  146. (tmp.left(2) != "-o") &&
  147. (tmp.left(2) != "-b") ) {
  148. str = QString("print") + printFormat() + tmp;
  149. }
  150. }
  151. QString result;
  152. bool w = oChildManager->command(str, result);
  153. if (w) {
  154. if (result.length() > 0) {
  155. if (oGraph == true) {
  156. if (result.left(6) == "struct" || result.left(6) == "union") {
  157. oParser->clearDebugString();
  158. oParser->setString(result);
  159. oParser->parseStruct();
  160. if (oParser->error()) {
  161. CParseView* pv = new CParseView(oParser, 0);
  162. pv->setFont(qApp->font());
  163. pv->exec();
  164. delete pv;
  165. }
  166. if (oParser->root() != 0) {
  167. // search address in command string
  168. int pos = str.find("0x", 0, false);
  169. if (pos != -1) {
  170. QString addr = getAddressFromExpression(str);
  171. // Address found. Store in root node.
  172. if (addr.length() > 2) {
  173. TreeNode* root = oParser->root();
  174. root->value = addr;
  175. }
  176. }
  177. QString type = getTypeFromExpression(str);
  178. if (!type.isEmpty()) {
  179. createTree(con, type);
  180. }
  181. else {
  182. emit sigErrToConsole(con, tr("Invalid type") + "\n");
  183. }
  184. }
  185. }
  186. else if (str.left(4) == "task") {
  187. PRINT(cerr << "graph task requested" << endl);
  188. oParser->setString(result);
  189. oParser->parseTaskList();
  190. if (!oParser->error()) {
  191. emit sigTaskList(&oParser->taskList());
  192. }
  193. else {
  194. PRINT(cerr << "Parse error in task list" << endl);
  195. }
  196. }
  197. else if (str.find(" print")) { // assuming pointer to scalar
  198. CListView* lv = new CListView(0);
  199. lv->addColumn(tr("Name"));
  200. lv->addColumn(tr("Value"));
  201. lv->addColumn(tr("Type"));
  202. lv->setSorting(-1);
  203. lv->setFindColumn(0);
  204. lv->setMinimumSize(200, 100);
  205. QString type = getTypeFromExpression(str);
  206. dereferencePointerType(type);
  207. QString addr = getAddressFromExpression(str);
  208. removeTypeInfo(result);
  209. if (result.right(CMD_PROMPT_LEN) == CMD_PROMPT) {
  210. result.truncate(result.length() - CMD_PROMPT_LEN);
  211. }
  212. result = result.simplifyWhiteSpace();
  213. StructViewItem* lvi;
  214. lvi = new StructViewItem(lv);
  215. lvi->setType(type);
  216. lvi->setPixmapType(Scalar);
  217. lvi->setText(0, "*(" + addr + ")");
  218. lvi->setText(1, result);
  219. lvi->setText(2, type);
  220. emit sigNewGraph(lv);
  221. if (lv->parentWidget() == 0) { // object is unused
  222. delete lv;
  223. }
  224. }
  225. oGraph = false;
  226. }
  227. else {
  228. emit sigToConsole(con, result /*+ CMD_PROMPT*/);
  229. }
  230. }
  231. else {
  232. emit sigToConsole(con, CMD_PROMPT);
  233. }
  234. }
  235. else {
  236. emit sigErrToConsole(con, result + CMD_PROMPT);
  237. oGraph = false;
  238. }
  239. }
  240. void
  241. QLcrashDoc::slotRestart()
  242. {
  243. oQuitAfterChildExit = false;
  244. oChildManager->killChild();
  245. sigToConsole(0, "\n");
  246. // prevent qlcrash from exiting if call of lcrash fails
  247. oInitialTimer->start(1000, true);
  248. setLCrashPath(oConfigManager->item(CFG_GRP_FILES, CFG_ATT_FILES_LCRASH, LCRASH_DEFAULT_PATH));
  249. runCrash();
  250. }
  251. void
  252. QLcrashDoc::slotChildDied()
  253. {
  254. if (oChildManager->retval() != 0) {
  255. cerr << tr("lcrash exited with an error.") << endl;
  256. }
  257. if (oQuitAfterChildExit) {
  258. emit sigExit(false);
  259. }
  260. else {
  261. emit sigToConsole(0, tr("lcrash exited.") + "\n");
  262. }
  263. }
  264. void
  265. QLcrashDoc::slotInitialTimeout()
  266. {
  267. // oQuitAfterChildExit = true;
  268. if (lcrashIsReady)
  269. emit sigLCrashReady();
  270. }
  271. void
  272. QLcrashDoc::runCrash()
  273. {
  274. if (!oChildManager->valid()) {
  275. QMessageBox::critical(
  276. 0,
  277. stdCaption(tr("Error")),
  278. tr("Cannot execute lcrash. Please check the program settings\nand restart lcrash with File->Restart.")
  279. );
  280. }
  281. else {
  282. oWaitForInit = true;
  283. lcrashIsReady = false;
  284. emit sigBusy(true);
  285. if (!oLcrashArgs.isEmpty()) {
  286. oChildManager->setArgs(oLcrashArgs);
  287. }
  288. oChildManager->forkChild();
  289. oChildManager->setSignalOnTimeout(SIGINT);
  290. }
  291. }
  292. void
  293. QLcrashDoc::setLCrashPath(const QString path)
  294. {
  295. #if 0
  296. oChildManager->setChildPath(path);
  297. // do some sanity checks
  298. if (!oChildManager->exists()) {
  299. QMessageBox::critical(
  300. 0,
  301. stdCaption(tr("Error")),
  302. tr("Could not find lcrash at specified position.")
  303. );
  304. }
  305. else if (!oChildManager->executable()) {
  306. QMessageBox::critical(
  307. 0,
  308. stdCaption(tr("Error")),
  309. tr("You do not have the permission to execute the\nspecified file.")
  310. );
  311. }
  312. #endif
  313. }
  314. void
  315. QLcrashDoc::loadConfig()
  316. {
  317. setLCrashPath(oConfigManager->item(CFG_GRP_FILES, CFG_ATT_FILES_LCRASH, LCRASH_DEFAULT_PATH));
  318. // save directory defaults to the user's home dir
  319. oLastSaveDir = oConfigManager->homeDir();
  320. }
  321. void
  322. QLcrashDoc::createTree(CNConsole* con, QString typeHint)
  323. {
  324. TreeNode* root = oParser->root();
  325. if (root == 0) {
  326. emit sigErrToConsole(con, tr("Cannot create struct view") + "\n");
  327. return;
  328. }
  329. CListView* lv = new CListView(0);
  330. lv->addColumn(tr("Name"));
  331. lv->addColumn(tr("Value"));
  332. lv->addColumn(tr("Type"));
  333. lv->setSorting(-1);
  334. lv->setFindColumn(0);
  335. lv->setMinimumSize(200, 100);
  336. // traverse the tree created by the parser and build a QListView
  337. createTreeTraverse(root, lv, typeHint);
  338. emit sigNewGraph(lv);
  339. if (lv->parentWidget() == 0) {
  340. delete lv;
  341. }
  342. }
  343. void
  344. QLcrashDoc::createTreeTraverse(TreeNode* root, CListView* rootItem, QString typeHint)
  345. {
  346. // prepare root node...
  347. StructViewItem* item = new StructViewItem(rootItem);
  348. item->setType(root->name);
  349. item->setPixmapType(root->type);
  350. item->setText(0, root->name);
  351. item->setText(1, root->value);
  352. item->setType((root->name.length() > 0) ? root->name : typeHint);
  353. TreeNode* walker = root->childList.first();
  354. // get struct info. use type hint from caller if lcrash does not return the type of the structure
  355. QDict<QString>* map = structInfo(item->type());
  356. // also use type hint for the tree itself, if we can't obtain a type info from the print output
  357. if (item->text(0).length() == 0) {
  358. item->setText(0, typeHint);
  359. }
  360. // ...and continue with its children
  361. StructViewItem* after = 0;
  362. while (walker != 0) {
  363. createTreeTraverse(walker, item, map, &after, root->name);
  364. walker = root->childList.next();
  365. }
  366. // expand tree (first level)
  367. item->setOpen(true);
  368. }
  369. void
  370. QLcrashDoc::createTreeTraverse(TreeNode* parentNode, StructViewItem* parentItem, QDict<QString>* theMap, StructViewItem** after, const QString& pName)
  371. {
  372. if (parentNode == 0) {
  373. return;
  374. }
  375. StructViewItem* item = 0; // "0" to avoid a compiler warning
  376. QString type;
  377. // the tree might contain null entries which contains the children of the parent node
  378. if (parentNode->type != Null) {
  379. #ifdef WIN32
  380. #pragma warning(push)
  381. #pragma warning(disable:4390)
  382. #endif
  383. if (parentNode->name == "0") { // to set a `conditional' breakpoint in gdb
  384. if (parentNode);
  385. }
  386. #ifdef WIN32
  387. #pragma warning(pop)
  388. #endif
  389. item = (*after == 0) ? new StructViewItem(parentItem) : new StructViewItem(parentItem, *after);
  390. // item->setPixmapType(parentNode->type);
  391. item->setText(0, parentNode->name);
  392. *after = item;
  393. if (parentNode->type == Array) {
  394. type = parentNode->arrayType;
  395. }
  396. else if (parentNode->type == ArrayStruct) {
  397. type = parentNode->value;
  398. }
  399. else { // Struct and Scalar
  400. type = parentNode->name;
  401. if (type != QString::null && theMap != 0) {
  402. QString* tname = theMap->find(type);
  403. if (tname != 0) {
  404. PRINT(cerr << theMap << " " << parentNode->name << endl);
  405. type = *tname;
  406. }
  407. else {
  408. type = "?";
  409. }
  410. }
  411. else {
  412. type = "?";
  413. }
  414. }
  415. item->setPixmapType((type.findRev("*") == -1) ? parentNode->type : Pointer);
  416. item->setType(type);
  417. if (parentNode->type == Scalar || parentNode->type == Array) {
  418. item->setText(1, parentNode->value);
  419. }
  420. item->setText(2, type);
  421. }
  422. else {
  423. item = parentItem;
  424. *after = 0;
  425. }
  426. // get type information for child tree
  427. if ((parentNode->type == Struct || parentNode->type == ArrayStruct)) {
  428. // in case of an array struct, the type is stored as 'value' attribute :(
  429. QString tmp = (parentNode->type == Struct) ? parentNode->name : parentNode->value;
  430. QString* tname = 0;
  431. if (!tmp.isEmpty()) {
  432. tname = (theMap != 0) ? theMap->find(tmp) : 0;
  433. /*
  434. if (tname != 0) {
  435. theMap = structInfo(*tname);
  436. }
  437. */
  438. /*
  439. else if (parentNode->type == ArrayStruct && type[0] != '(') {
  440. theMap = structInfo(tmp);
  441. }
  442. */
  443. theMap = structInfo(pName);
  444. }
  445. } // array elments are of the same type as their parent node, so get type of such a parent
  446. else if (parentNode->type == Array && parentNode->childList.count() > 0 && theMap != 0) {
  447. QString* tmp = theMap->find(parentNode->name);
  448. if (tmp != 0) {
  449. parentNode->arrayType = *tmp;
  450. // this is a hack to set the array type correctly for display
  451. item->setText(2, *tmp);
  452. item->setType(*tmp);
  453. }
  454. else {
  455. parentNode->arrayType = "?";
  456. }
  457. }
  458. TreeNode* walker = parentNode->childList.first();
  459. StructViewItem* tmp = 0;
  460. type = parentNode->arrayType;
  461. if (parentNode->type == Array) { // strip array size from type name for array elements
  462. if (type.right(1) == "]") {
  463. type.truncate(type.findRev("["));
  464. }
  465. }
  466. while (walker != 0) {
  467. // walker is an array -> assign its type. Be aware of the null-nodes (assign type if parent is array)!
  468. if (walker->type == Array || parentNode->type == Array) {
  469. walker->arrayType = type;
  470. }
  471. // build `path' from this attribute to the root data type
  472. QString cName = pName;
  473. if (walker->type != Null) { // this is a node type, not a data type :-O
  474. if (walker->type != Array) { // ArrayStruct || Struct
  475. if (walker->type == Struct) {
  476. cName = cName + "." + walker->name;
  477. }
  478. else { // ArrayStruct
  479. // if (parentNode->type == Null) {
  480. cName = type;
  481. // }
  482. }
  483. }
  484. else {
  485. /* keep cName */
  486. }
  487. }
  488. else { // save name
  489. // walker->name = parentNode->name;
  490. }
  491. createTreeTraverse(walker, item, theMap, &tmp, cName);
  492. walker = parentNode->childList.next();
  493. }
  494. }
  495. QDict<QString>*
  496. QLcrashDoc::structInfo(QString str)
  497. {
  498. if (str == QString::null || str[0] == '(') {
  499. return 0;
  500. }
  501. /** `whatis' returns weird results if there are no parenthesis around the expression.
  502. But this doesn't work with subtypes.
  503. */
  504. QString search = str;
  505. if (str.find('.') == -1) { // simple expression
  506. search.prepend("(");
  507. search.append(")");
  508. }
  509. QDict<QString>* list = oTypeMap[str];
  510. if (list == 0) {
  511. /* O.k. retrieve information from lcrash */
  512. QString q;
  513. PRINT(cerr << "whatis " + search + " ...");
  514. bool w = oChildManager->command(QString("whatis ") + search + "\n", q);
  515. PRINT(cerr << "done" << endl);
  516. if (w && !q.isEmpty()) {
  517. oParser->clearDebugString();
  518. oParser->setString(q);
  519. oParser->parseWhatIs();
  520. if (oParser->error()) {
  521. CParseView* pv = new CParseView(oParser, 0);
  522. pv->setFont(qApp->font());
  523. pv->exec();
  524. delete pv;
  525. }
  526. else {
  527. list = oParser->typeMap();
  528. if (list != 0) {
  529. oTypeMap.insert(str, list);
  530. }
  531. }
  532. }
  533. }
  534. return list;
  535. }
  536. CListView*
  537. QLcrashDoc::getTree(const QString& name, const QString& addr, const QString& type)
  538. {
  539. QString result;
  540. bool w = oChildManager->command(
  541. QString("print ") + printFormat() + "*(" + type + ") " + addr, result);
  542. if (w) {
  543. if (result.left(6) == "struct" || result.left(6) == "union") {
  544. oGraph = true;
  545. oParser->setString(result);
  546. oParser->parseStruct();
  547. if (oParser->error()) {
  548. CParseView* pv = new CParseView(oParser, 0);
  549. pv->setFont(qApp->font());
  550. pv->exec();
  551. delete pv;
  552. }
  553. TreeNode* root = oParser->root();
  554. result = result.stripWhiteSpace();
  555. if (root != 0) {
  556. CListView* lv = new CListView(0);
  557. lv->addColumn(tr("Name"));
  558. lv->addColumn(tr("Value"));
  559. lv->addColumn(tr("Type"));
  560. lv->setSorting(-1);
  561. lv->setFindColumn(0);
  562. lv->setMinimumSize(200, 100);
  563. root->value = addr;
  564. QString root_t = type;
  565. if (root_t.right(1) == "*") {
  566. root_t.truncate(root_t.length() - 1);
  567. }
  568. createTreeTraverse(root, lv, root_t);
  569. oGraph = false;
  570. return lv;
  571. }
  572. }
  573. else { // no struct
  574. QString ntype = type;
  575. CListView* lv = new CListView(0);
  576. if (result.right(CMD_PROMPT_LEN) == CMD_PROMPT) {
  577. result.truncate(result.length() - CMD_PROMPT_LEN);
  578. }
  579. result = result.stripWhiteSpace();
  580. lv->addColumn(tr("Name"));
  581. lv->addColumn(tr("Value"));
  582. lv->addColumn(tr("Type"));
  583. // lv->header()->hide();
  584. lv->setMinimumSize(200, 40);
  585. if (ntype.right(1) == "*") {
  586. ntype.truncate(type.length() - 1);
  587. }
  588. StructViewItem* svi = new StructViewItem(lv);
  589. svi->setText(0, name);
  590. svi->setText(1, result);
  591. svi->setText(2, ntype);
  592. svi->setType(ntype);
  593. svi->setPixmapType((ntype.findRev("*") == -1) ? Scalar : Pointer);
  594. return lv;
  595. }
  596. }
  597. else {
  598. emit sigErrToConsole(0, result + "\n" + CMD_PROMPT);
  599. }
  600. return 0;
  601. }
  602. CListView*
  603. QLcrashDoc::getArray(const QString& addr, const QString& type, int number)
  604. {
  605. CListView* retList = 0;
  606. // get size info
  607. int size = sizeinfo(type, "");
  608. if (size > 0) {
  609. // get address
  610. bool ret;
  611. unsigned long long val = (UINT64)strtoull(addr.mid(2).latin1(), 0, 16);
  612. if (ret) {
  613. // O.k., create list
  614. CListView* lv = new CListView(0, "arrayList");
  615. lv->addColumn(tr("Name"));
  616. lv->addColumn(tr("Value"));
  617. lv->addColumn(tr("Type"));
  618. lv->setSorting(-1);
  619. lv->setMinimumSize(200, 100);
  620. StructViewItem* svi = new StructViewItem(lv);
  621. svi->setText(0, type);
  622. svi->setType(type);
  623. svi->setPixmapType(Array);
  624. // arrays of pointers are handled different from `normal' arrays
  625. bool pointer = (type.findRev('*') != -1) ? true : false;
  626. // ensure that item are appended to the tree at the end
  627. StructViewItem* after = 0;
  628. if (pointer) {
  629. /* pointers are a bit more difficult than other types since
  630. we have to request the contents of each element from lcrash
  631. */
  632. //! assuming that `sizeof(long) == sizeof(void*)' on dump source platform
  633. size = targetWordSize();
  634. for (int i = 0; i < number; i++) {
  635. QString result;
  636. char newAddrStr[100];
  637. sprintf(newAddrStr, "%llx",val);
  638. bool ret = oChildManager->command("print *(void**) 0x" + QString::fromLatin1(newAddrStr), result);
  639. removeTypeInfo(result);
  640. if (result.right(CMD_PROMPT_LEN) == CMD_PROMPT) {
  641. result.truncate(result.length() - CMD_PROMPT_LEN);
  642. }
  643. val += size;
  644. if (ret) {
  645. result = result.stripWhiteSpace();
  646. StructViewItem* svch = after ? new StructViewItem(svi, after) : new StructViewItem(svi);
  647. after = svch;
  648. svch->setText(0, QString::number(i));
  649. svch->setText(1, result);
  650. svch->setText(2, type);
  651. svch->setType(type);
  652. svch->setPixmapType(Pointer);
  653. }
  654. else { // failed
  655. delete lv;
  656. }
  657. }
  658. }
  659. else {
  660. for (int i = 0; i < number; i++) {
  661. StructViewItem* svch = after ? new StructViewItem(svi, after) : new StructViewItem(svi);
  662. char newAddrStr[100];
  663. sprintf(newAddrStr, "%llx",val);
  664. after = svch;
  665. svch->setText(0, QString::number(i));
  666. svch->setText(1, QString("0x") + QString::fromLatin1(newAddrStr));
  667. svch->setText(2, type + "*");
  668. svch->setType(type + "*"); // we display an array of pointers
  669. svch->setPixmapType(Pointer);
  670. val += size;
  671. }
  672. }
  673. svi->setOpen(true);
  674. lv->setCaption(type + "[" + QString::number(number) + "]" + "@" + addr);
  675. retList = lv;
  676. }
  677. }
  678. return retList;
  679. }
  680. int
  681. QLcrashDoc::getOffset(const QString& typeName, const QString& memberName)
  682. {
  683. bool ret;
  684. QString result;
  685. ret = oChildManager->command("offset " + typeName + "." + memberName, result);
  686. if(ret) {
  687. QRegExp r("[\\S]+[\\s]+([0-9]+)[\\s]+[\\S]+\n");
  688. if(r.search(result, 0) == -1){
  689. printErr("ERR: Result of offset command is invalid\n");
  690. return 0;
  691. }
  692. return atoi(r.cap(1));
  693. } else {
  694. printErr(result);
  695. return 0;
  696. }
  697. }
  698. CListView*
  699. QLcrashDoc::getWalk(const QString& name, const QString& addr, const QString& type)
  700. {
  701. bool ret;
  702. QString result;
  703. // determine if `name' is a list_head
  704. ret = oChildManager->command("whatis " + type + "." + name, result);
  705. if (ret) {
  706. if (result.left(16) == "struct list_head") {
  707. return getListHead(name, addr, type);
  708. }
  709. }
  710. else {
  711. printErr(result);
  712. return 0;
  713. }
  714. ret = oChildManager->command("print ((" + type + "*)" + addr + ")->" + name, result);
  715. if (ret) {
  716. removeTypeInfo(result);
  717. // remove trailing prompt
  718. if (result.right(CMD_PROMPT_LEN) == CMD_PROMPT) {
  719. result.truncate(result.length() - CMD_PROMPT_LEN);
  720. }
  721. result = result.stripWhiteSpace();
  722. CListView* lv = new CListView(0);
  723. lv->addColumn(tr("Name"));
  724. lv->addColumn(tr("Value"));
  725. lv->addColumn(tr("Type"));
  726. lv->setMinimumSize(200, 100);
  727. lv->setSorting(-1);
  728. StructViewItem* svi = new StructViewItem(lv);
  729. StructViewItem* after = 0;
  730. svi->setText(0, type + "." + name);
  731. svi->setText(1, addr);
  732. svi->setType(type);
  733. svi->setPixmapType(Array);
  734. int i = 0;
  735. Avl<QString> aset;
  736. do {
  737. aset.insert(result);
  738. StructViewItem* svch = after ? new StructViewItem(svi, after) : new StructViewItem(svi);
  739. after = svch;
  740. svch->setText(0, QString::number(i++));
  741. svch->setText(1, result);
  742. svch->setText(2, type + "*");
  743. svch->setType(type + "*");
  744. svch->setPixmapType(Pointer);
  745. // avoid infinite recursion
  746. if (i > WALKMAX) {
  747. sigErrToConsole(0, tr("Walk has reached WALKMAX (%1)").arg(QString::number(WALKMAX)));
  748. break;
  749. }
  750. ret = oChildManager->command("print ((" + type + "*)" + result + ")->" + name, result);
  751. if(ret){
  752. removeTypeInfo(result);
  753. }
  754. // remove trailing prompt
  755. if (ret && result.right(CMD_PROMPT_LEN) == CMD_PROMPT) {
  756. result.truncate(result.length() - CMD_PROMPT_LEN);
  757. }
  758. result = result.stripWhiteSpace();
  759. } while (ret && result != "0x0" && result[0].latin1() != '(' && !aset.search(result));
  760. svi->setOpen(true);
  761. lv->setCaption("walk:" + type + "." + name + "@" + addr);
  762. return lv;
  763. }
  764. return 0;
  765. }
  766. CListView*
  767. QLcrashDoc::getListHead(const QString& name, const QString& addr, const QString& type)
  768. {
  769. QString result;
  770. CListView* tree = 0;
  771. bool ret = oChildManager->command("walk -h n -t " + type + " " + name + " " + addr, result);
  772. if (ret) {
  773. QList<QString>* list = new QList<QString>;
  774. list->setAutoDelete(true);
  775. // create a list of addresses using the first column
  776. const int len = result.length();
  777. for (int i = 0; i < len; i++) {
  778. // ignore white space
  779. while (i < len && (result[i].latin1() == ' ' || result[i].latin1() == '\t'))
  780. i++;
  781. if (isdigit(result[i].latin1())) {
  782. int s = i++;
  783. while (i < len && isalnum(result[i].latin1()))
  784. i++;
  785. list->append(new QString(result.mid(s, i - s)));
  786. }
  787. // ignore the rest of the line
  788. while (i < len && result[i].latin1() != '\n')
  789. i++;
  790. }
  791. // lreate a list view
  792. CListView* lv = new CListView(0);
  793. lv->addColumn(tr("Name"));
  794. lv->addColumn(tr("Value"));
  795. lv->addColumn(tr("Type"));
  796. lv->setMinimumSize(200, 100);
  797. lv->setSorting(-1);
  798. StructViewItem* svi = new StructViewItem(lv);
  799. StructViewItem* after = 0;
  800. svi->setText(0, type + "." + name);
  801. svi->setText(1, addr);
  802. svi->setType(type);
  803. svi->setPixmapType(Array);
  804. QString* walker = list->first();
  805. int n = 0;
  806. while (walker != 0) {
  807. if (walker->length() > 1) {
  808. StructViewItem* svch = after ? new StructViewItem(svi, after) : new StructViewItem(svi);
  809. after = svch;
  810. svch->setText(0, QString::number(n++));
  811. svch->setText(1, *walker);
  812. svch->setText(2, type + "*");
  813. svch->setType(type + "*");
  814. svch->setPixmapType(Pointer);
  815. }
  816. walker = list->next();
  817. }
  818. delete list;
  819. svi->setOpen(true);
  820. lv->setCaption("walk:" + type + "." + name + "@" + addr);
  821. tree = lv;
  822. }
  823. return tree;
  824. }
  825. void
  826. QLcrashDoc::slotStderrFromChild(QString str)
  827. {
  828. emit sigErrToConsole(0, str);
  829. }
  830. void
  831. QLcrashDoc::slotStdoutFromChild(QString str)
  832. {
  833. if (oWaitForInit) {
  834. if (str.right(CMD_PROMPT_LEN) == CMD_PROMPT) {
  835. oWaitForInit = false;
  836. lcrashIsReady = true;
  837. oInitialTimer->start(1000, true);
  838. // emit sigLCrashReady();
  839. // Initial newline
  840. emit sigToConsole(0, "\n");
  841. }
  842. }
  843. if (oGraph == false) {
  844. emit sigToConsole(0, str);
  845. }
  846. }
  847. void
  848. QLcrashDoc::printTypeInfo(const QString& type, const QString& name)
  849. {
  850. if (type == "" || type == "?") {
  851. sigErrToConsole(0, tr("Could not get type info") + "\n");
  852. }
  853. else {
  854. int size = sizeinfo(type, name);
  855. if (size > 0) {
  856. emit sigToConsole(0, QString("\n") + tr("Type") + ": " + type + "\n");
  857. emit sigToConsole(0, tr("sizeof") + ": " + QString::number(size) + " Bytes\n");
  858. }
  859. else {
  860. sigErrToConsole(0, tr("Could not get type info") + "\n");
  861. }
  862. }
  863. emit sigToConsole(0, CMD_PROMPT);
  864. }
  865. void
  866. QLcrashDoc::printWhatis(const QString& type, const QString& name)
  867. {
  868. if (type.length() == 0 || type == "?") {
  869. sigErrToConsole(0, tr("'whatis' failed") + "\n");
  870. }
  871. else {
  872. QString result;
  873. bool w = oChildManager->command("whatis " + type, result);
  874. if (w) {
  875. emit sigToConsole(0, type + " = " + result + "\n");
  876. }
  877. else {
  878. w = oChildManager->command("whatis " + name, result);
  879. if (w) {
  880. emit sigToConsole(0, name + " = " + result + "\n");
  881. }
  882. else {
  883. emit sigErrToConsole(0, tr("'whatis' failed") + ".\n");
  884. }
  885. }
  886. }
  887. emit sigToConsole(0, CMD_PROMPT);
  888. }
  889. void
  890. QLcrashDoc::printTrace(const QString& addr)
  891. {
  892. QString result;
  893. bool w = oChildManager->command(QString("trace") + " " + addr, result);
  894. if (w) {
  895. sigToConsole(0, (QString) "\n" + result + "\n");
  896. }
  897. emit sigToConsole(0, CMD_PROMPT);
  898. }
  899. int
  900. QLcrashDoc::sizeinfo(const QString& type, const QString& name)
  901. {
  902. // a pointer has always the same size
  903. if (type.right(1) == "*") {
  904. return targetWordSize();
  905. }
  906. // compare types with builtin types
  907. Avl<QString> set;
  908. QStringList list = QStringList::split(' ', type);
  909. for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
  910. set.insert(*it);
  911. }
  912. // check for 'long long'
  913. Avl<QString>::iterator ait = set.find("long");
  914. if (ait != set.end()) {
  915. // is there a second 'long' ?
  916. if (++ait != set.end() && *ait == "long") {
  917. return 8;
  918. }
  919. return targetWordSize();
  920. }
  921. if (set.search("int")) {
  922. return 4;
  923. }
  924. if (set.search("short")) {
  925. return 2;
  926. }
  927. if (set.search("char")) {
  928. return 1;
  929. }
  930. #ifndef WIN32
  931. #warning "This could become a problem..."
  932. #endif
  933. if (set.search("double")) {
  934. return sizeof(double);
  935. }
  936. if (set.search("float")) {
  937. return sizeof(float);
  938. }
  939. // not a builtin type
  940. QString result;
  941. bool ret = oChildManager->command("sizeof " + type, result);
  942. if (!ret) { // try 'whatis' followed by 'sizeof'
  943. ret = oChildManager->command("whatis (" + type + ")", result);
  944. if (ret) {
  945. ret = oChildManager->command("sizeof " + result, result);
  946. }
  947. if (!ret && name.length() > 0) { // try attribute name
  948. ret = oChildManager->command("sizeof " + name, result);
  949. }
  950. }
  951. if (ret) {
  952. QString num = "";
  953. int i, len = result.length(),match_len;
  954. // skip to colon
  955. QRegExp r(": *[0-9]");
  956. i=r.match(result,0,&match_len);
  957. i+=match_len -1;
  958. // copy number digit by digit
  959. for (; i < len; i++) {
  960. char ch = result.at(i).latin1();
  961. if (!isdigit(ch)) {
  962. break;
  963. }
  964. num.append(ch);
  965. }
  966. int val = num.toInt(&ret);
  967. return ret ? val : 0;
  968. }
  969. else {
  970. sigErrToConsole(0, QString("\n") + tr("Size of `%1' unknown").arg(type) + "\n");
  971. }
  972. return 0;
  973. }
  974. void
  975. QLcrashDoc::print(const QString& str)
  976. {
  977. sigToConsole(0, str + "\n" + CMD_PROMPT);
  978. }
  979. void
  980. QLcrashDoc::printErr(const QString& str)
  981. {
  982. sigErrToConsole(0, str + "\n" + CMD_PROMPT);
  983. }
  984. QString
  985. QLcrashDoc::printFormat() const
  986. {
  987. int idx = oConfigManager->item(CFG_GRP_GRAPH, CFG_ATT_GRAPH_PRINTFORMAT, 0);
  988. if (idx > 0) {
  989. switch (idx) {
  990. case 1:
  991. return " -x ";
  992. case 2:
  993. return " -d ";
  994. case 3:
  995. return " -o ";
  996. case 4:
  997. return " -b ";
  998. default:
  999. return " ";
  1000. }
  1001. }
  1002. return " ";
  1003. }
  1004. const unsigned char*
  1005. QLcrashDoc::getDump(const QString& addr)
  1006. {
  1007. if (oWaitForInit) {
  1008. return 0;
  1009. }
  1010. unsigned char* cptr = oDumpCache->find(addr);
  1011. if (cptr == 0) {
  1012. QString sAddr = QString("0x") + addr;
  1013. QString result;
  1014. bool ret = oChildManager->command("dump -B " + sAddr + " 16", result);
  1015. if (ret) {
  1016. cptr = new unsigned char[16];
  1017. oDumpCache->insert(addr, cptr);
  1018. int len = result.length();
  1019. int i;
  1020. // skip to the first colon
  1021. for (i = 0; i < len && result.at(i).latin1() != ':'; i++) { /* empty */ }
  1022. i += 2;
  1023. unsigned char ch;
  1024. int idx = 0, s = -1;
  1025. while (i < len && (ch = result.at(i).latin1()) != ':') {
  1026. i++;
  1027. if (ch == ' ') {
  1028. assert(idx < 16);
  1029. cptr[idx++] = s;
  1030. s = -1;
  1031. continue;
  1032. }
  1033. s = (s == -1) ? hexCharToInt(ch) * 16 : s + hexCharToInt(ch);
  1034. }
  1035. }
  1036. }
  1037. return cptr;
  1038. }
  1039. int
  1040. QLcrashDoc::targetSetup()
  1041. {
  1042. QString result;
  1043. bool ret = oChildManager->command("info -s endian", result);
  1044. if (ret) {
  1045. if(result.mid(0,6) == "little"){
  1046. oTargetEndian=little;
  1047. } else if(result.mid(0,3) == "big") {
  1048. oTargetEndian=big;
  1049. } else {
  1050. cerr << "QLcrashDoc::targetLittleEndian: info -s failed\n";
  1051. oTargetEndian=unknown;
  1052. }
  1053. } else {
  1054. cerr << "QLcrashDoc::targetLittleEndian: info -s failed\n";
  1055. oTargetEndian=unknown;
  1056. }
  1057. ret = oChildManager->command("info -s psize", result);
  1058. if (ret) {
  1059. if(result.mid(0,2) == "32"){
  1060. oTargetWordSize=4;
  1061. } else if(result.mid(0,2) == "64"){
  1062. oTargetWordSize=8;
  1063. } else {
  1064. cerr << "QLcrashDoc::targetWordSize: info -s psize returned '" << result << "'\n";
  1065. oTargetWordSize=-1;
  1066. }
  1067. } else {
  1068. cerr << "QLcrashDoc::targetWordSize: info -s psize failed\n";
  1069. oTargetWordSize=-1;
  1070. }
  1071. return 0;
  1072. }
  1073. bool
  1074. QLcrashDoc::targetLittleEndian() const
  1075. {
  1076. if(oTargetEndian == little)
  1077. return true;
  1078. else
  1079. return false;
  1080. }
  1081. int
  1082. QLcrashDoc::targetWordSize() const
  1083. {
  1084. if(oTargetWordSize == -1)
  1085. return sizeof(long);
  1086. else
  1087. return oTargetWordSize;
  1088. }
  1089. QStringList*
  1090. QLcrashDoc::s390AvailableLogs()
  1091. {
  1092. QStringList* list = new QStringList;
  1093. QString result;
  1094. bool ret = oChildManager->command("s390dbf", result);
  1095. if (ret) {
  1096. *list = QStringList::split('\n', result);
  1097. int count = list->count();
  1098. if (count > 2) {
  1099. QStringList::Iterator it = list->begin();
  1100. it = list->remove(it);
  1101. it = list->remove(it);
  1102. for (int i = 2; i < count - 1; i++) {
  1103. (*it) = (*it).simplifyWhiteSpace();
  1104. (*it) = (*it).mid(2);
  1105. ++it;
  1106. }
  1107. list->remove(it);
  1108. }
  1109. }
  1110. return list;
  1111. }
  1112. QStringList*
  1113. QLcrashDoc::s390AvailableViews(const QString& log)
  1114. {
  1115. QStringList* list = new QStringList;
  1116. QString result;
  1117. bool ret = oChildManager->command("s390dbf " + log, result);
  1118. if (ret) {
  1119. *list = QStringList::split('\n', result);
  1120. int count = list->count();
  1121. if (count > 3) {
  1122. QStringList::Iterator it = list->begin();
  1123. it = list->remove(it);
  1124. it = list->remove(it);
  1125. for (int i = 2; i < count - 2; i++) {
  1126. (*it) = (*it).simplifyWhiteSpace();
  1127. // (*it) = QStringList::split(' ', (*it).mid(2)).first();
  1128. (*it) = (*it).mid(2);
  1129. ++it;
  1130. }
  1131. it = list->remove(it);
  1132. list->remove(it);
  1133. }
  1134. }
  1135. return list;
  1136. }
  1137. QString
  1138. QLcrashDoc::s390dbfText(const QString& log, const QString& view)
  1139. {
  1140. QString result;
  1141. oChildManager->command("s390dbf " + log + " " + view, result);
  1142. // remove trailing newline and prompt
  1143. if (result.right(CMD_PROMPT_LEN) == CMD_PROMPT) {
  1144. result.truncate(result.length() - CMD_PROMPT_LEN);
  1145. }
  1146. while (!result.isEmpty() && result.right(1) == "\n") {
  1147. result.truncate(result.length() - 1);
  1148. }
  1149. return result;
  1150. }
  1151. void
  1152. QLcrashDoc::s390dbfSaveToFile(const QString& log, const QString& view, const QString& file)
  1153. {
  1154. QString result;
  1155. bool ret = oChildManager->command("s390dbf -w " + file + " " + log + " " + view, result);
  1156. if (!ret) {
  1157. emit printErr(result);
  1158. }
  1159. }
  1160. bool
  1161. QLcrashDoc::haveDebugFeature()
  1162. {
  1163. if (oWaitForInit) {
  1164. cerr << "QLcrashDoc::haveDebugFeature() called during initialization phase." << endl;
  1165. return false;
  1166. }
  1167. if (oS390dbf == -1) {
  1168. QString result;
  1169. bool ret = oChildManager->command("s390dbf", result);
  1170. oS390dbf = ret ? 1 : 0;
  1171. }
  1172. return oS390dbf;
  1173. }
  1174. QString
  1175. QLcrashDoc::helpHomeURL()
  1176. {
  1177. #ifdef WIN32
  1178. #ifdef _DEBUG
  1179. return QString("file:/") + execdir() + "/../../Doc/Manual/index.html";
  1180. #else
  1181. return QString("file:/") + execdir() + "/Manual/index.html";
  1182. #endif
  1183. #else
  1184. return "file:/" DOCDIR "/index.html";
  1185. #endif
  1186. }
  1187. QString
  1188. QLcrashDoc::lastSaveDir() const
  1189. {
  1190. return oLastSaveDir;
  1191. }
  1192. void
  1193. QLcrashDoc::setLastSaveDir(const QString& lsd)
  1194. {
  1195. oLastSaveDir = lsd;
  1196. }
  1197. QString
  1198. QLcrashDoc::getTypeFromExpression(const QString& expr) const
  1199. {
  1200. int len = expr.length();
  1201. int i = expr.find("print");
  1202. int count = 0;
  1203. QString type;
  1204. if (i != -1) {
  1205. i += 5;
  1206. }
  1207. else {
  1208. i = 0;
  1209. }
  1210. for (; i < len; i++) {
  1211. if (expr[i].latin1() != ' ') {
  1212. break;
  1213. }
  1214. }
  1215. for (; i < len; i++) {
  1216. if (expr[i].latin1() == '*') {
  1217. count--;
  1218. }
  1219. else {
  1220. break;
  1221. }
  1222. }
  1223. for (; i < len; i++) {
  1224. if (expr[i].latin1() == '(') {
  1225. break;
  1226. }
  1227. }
  1228. while (i < len && !isalpha(expr[i].latin1())) {
  1229. i++;
  1230. }
  1231. char ch;
  1232. int start = i;
  1233. while (i < len && (isalpha((ch = expr[i].latin1()))||ch=='_'||ch==' '|| (isdigit(ch) && (start < i)) )) {
  1234. type += ch;
  1235. i++;
  1236. }
  1237. for (; i < len; i++) {
  1238. ch = expr[i].latin1();
  1239. switch (ch) {
  1240. case '*':
  1241. count++;
  1242. break;
  1243. case ')':
  1244. i = len;
  1245. break;
  1246. default:
  1247. continue;
  1248. }
  1249. }
  1250. for (i = 0; i < count; i++) {
  1251. type += '*';
  1252. }
  1253. return (count >= 0) ? type : QString::null;
  1254. }
  1255. QString
  1256. QLcrashDoc::getAddressFromExpression(const QString& expr) const
  1257. {
  1258. QString ret;
  1259. int pos = expr.find("0x");
  1260. if (pos >= 0) {
  1261. const int len = expr.length();
  1262. pos += 2;
  1263. ret = "0x";
  1264. while (pos < len && isxdigit(expr[pos].latin1())) {
  1265. ret += expr[pos];
  1266. pos++;
  1267. }
  1268. }
  1269. return ret;
  1270. }
  1271. QValueList<CDisassemble>
  1272. QLcrashDoc::getDisassemble(const QString& fkt)
  1273. {
  1274. QValueList<CDisassemble> list;
  1275. QString result;
  1276. bool ret = oChildManager->command("dis -F " + fkt, result);
  1277. if (ret) {
  1278. #ifdef USE_REGEX
  1279. regex_t reg;
  1280. regmatch_t sub[4];
  1281. ret = regcomp(
  1282. &reg,
  1283. "(0x[0-9a-f]+)[ \t]*(<[^>]+>):[ \t]*(.+)\n",
  1284. REG_EXTENDED | REG_NEWLINE
  1285. );
  1286. assert(!ret);
  1287. int offset = 0, len = result.length();
  1288. while (offset < len && regexec(&reg, result.latin1() + offset, 4, sub, 0) == 0) {
  1289. QString part;
  1290. CDisassemble cd;
  1291. part = result.mid(offset + sub[1].rm_so, sub[1].rm_eo - sub[1].rm_so);
  1292. cd.setAddr(part.simplifyWhiteSpace());
  1293. part = result.mid(offset + sub[2].rm_so, sub[2].rm_eo - sub[2].rm_so);
  1294. cd.setOffset(part.simplifyWhiteSpace());
  1295. part = result.mid(offset + sub[3].rm_so, sub[3].rm_eo - sub[3].rm_so);
  1296. cd.setMnemonic(part.simplifyWhiteSpace());
  1297. list.append(cd);
  1298. offset = offset + sub[0].rm_eo;
  1299. }
  1300. regfree(&reg);
  1301. #else
  1302. #if QT_VERSION >= 300
  1303. // New QT 3.0
  1304. QRegExp r("(0x[0-9a-f]+)[ \t]*(<[^>]+>):[ \t]*([^\\n]+)\n");
  1305. int offset = 0, len = result.length();
  1306. while (offset < len && (r.search(result, offset) >= 0)) {
  1307. CDisassemble cd;
  1308. cd.setAddr(r.cap(1).simplifyWhiteSpace());
  1309. cd.setOffset(r.cap(2).simplifyWhiteSpace());
  1310. cd.setMnemonic(r.cap(3).simplifyWhiteSpace());
  1311. list.append(cd);
  1312. offset += r.matchedLength();
  1313. }
  1314. #else
  1315. // Old QT < 3.0
  1316. QRegExp r("0x[0-9a-f]+[ \t]*<[^>]+>:[ \t]*[^\\n]+\\n");
  1317. QRegExp sub1("0x[0-9a-f]+");
  1318. QRegExp sub2("[ \t]*");
  1319. QRegExp sub3("<[^>]+>");
  1320. QRegExp sub4(":[ \t]*");
  1321. QRegExp sub5("[^\\n]+");
  1322. int offset = 0, len = result.length();
  1323. int rlen;
  1324. int rpos;
  1325. while (offset < len && ((rpos = r.match(result, offset, &rlen)) >= 0)) {
  1326. int slen;
  1327. CDisassemble cd;
  1328. sub1.match(result, rpos, &slen);
  1329. cd.setAddr(result.mid(rpos, slen).simplifyWhiteSpace());
  1330. rpos += slen;
  1331. sub2.match(result, rpos, &slen);
  1332. rpos += slen;
  1333. sub3.match(result, rpos, &slen);
  1334. cd.setOffset(result.mid(rpos, slen).simplifyWhiteSpace());
  1335. rpos += slen;
  1336. sub4.match(result, rpos, &slen);
  1337. rpos += slen;
  1338. sub5.match(result, rpos, &slen);
  1339. cd.setMnemonic(result.mid(rpos, slen).simplifyWhiteSpace());
  1340. list.append(cd);
  1341. offset += rlen;
  1342. }
  1343. #endif // !QT 3.0
  1344. #endif // !USE_REGEX
  1345. }
  1346. return list;
  1347. }
  1348. QValueList<CTraceItem>
  1349. QLcrashDoc::getTrace(const QString& addr)
  1350. {
  1351. QValueList<CTraceItem> list;
  1352. QString result;
  1353. bool ret = oChildManager->command("trace " + addr, result);
  1354. if (ret) {
  1355. int offset = 0, len = result.length();
  1356. // skip header and retrieve task name
  1357. while (offset < len && result[offset].latin1() != '(') {
  1358. offset++;
  1359. }
  1360. QString name;
  1361. offset++;
  1362. while (offset < len && result[offset].latin1() != ')') {
  1363. name.append(result[offset]);
  1364. offset++;
  1365. }
  1366. CTraceItem item;
  1367. item.setFunction(name);
  1368. list.append(item);
  1369. while (offset < len && !isdigit(result[offset].latin1())) {
  1370. offset++;
  1371. }
  1372. #ifdef USE_REGEX
  1373. regex_t reg;
  1374. regmatch_t sub[5];
  1375. ret = regcomp(
  1376. &reg,
  1377. "[ \t]*([0-9]+)[ \t]*([a-zA-Z0-9_]+)(\\+[0-9]+)?[ \t]*\\[(0x[0-9a-zA-F]+)\\][ \t]*\n",
  1378. REG_EXTENDED | REG_NEWLINE
  1379. );
  1380. assert(!ret);
  1381. while (offset < len && regexec(&reg, result.latin1() + offset, 5, sub, 0) == 0) {
  1382. QString part;
  1383. CTraceItem ci;
  1384. part = result.mid(offset + sub[1].rm_so, sub[1].rm_eo - sub[1].rm_so);
  1385. ci.setLevel(part);
  1386. part = result.mid(offset + sub[2].rm_so, sub[2].rm_eo - sub[2].rm_so);
  1387. ci.setFunction(part);
  1388. part = result.mid(offset + sub[3].rm_so, sub[3].rm_eo - sub[3].rm_so);
  1389. ci.setOffset(part);
  1390. part = result.mid(offset + sub[4].rm_so, sub[4].rm_eo - sub[4].rm_so);
  1391. ci.setAddress(part);
  1392. offset = offset + sub[0].rm_eo;
  1393. list.append(ci);
  1394. }
  1395. regfree(&reg);
  1396. #else
  1397. #if QT_VERSION >= 300
  1398. #warning QT3 QRegExp stuff is yet untested
  1399. QRegExp r("[ \t]*([0-9]+)[ \t]*([a-zA-Z0-9_]+)(\\+[0-9]+)?[ \t]*\\[(0x[0-9a-zA-F]+)\\][ \t]*\\n");
  1400. offset = r.search(result,offset);
  1401. while (offset < len && ((offset = r.search(result, offset)) >= 0)) {
  1402. CTraceItem ci;
  1403. ci.setLevel(r.cap(1));
  1404. ci.setFunction(r.cap(2));
  1405. ci.setOffset(r.cap(3));
  1406. ci.setAddress(r.cap(4));
  1407. list.append(ci);
  1408. offset += r.matchedLength();
  1409. }
  1410. #else
  1411. QRegExp r("[ \t]*[0-9]+[ \t]*[a-zA-Z0-9_]+\\+[0-9]+[ \t]*\\[0x[0-9a-zA-F]+\\][ \t]*\\n");
  1412. QRegExp r2("[ \t]*[0-9]+[ \t]*[a-zA-Z0-9_]+[ \t]*\\[0x[0-9a-zA-F]+\\][ \t]*\\n");
  1413. QRegExp sub1("[ \t]*");
  1414. QRegExp sub2("[0-9]+"); // cap
  1415. //QRegExp sub3 = sub1;
  1416. QRegExp sub4("[a-zA-Z0-9_]+"); // cap
  1417. QRegExp sub5("\\+[0-9]+"); // cap
  1418. QRegExp sub6("[ \t]*\\[");
  1419. QRegExp sub7("0x[0-9a-zA-F]+"); // cap
  1420. //QRegExp sub8("\\][ \t]*\\n");
  1421. int rlen;
  1422. int rlen2;
  1423. int rpos;
  1424. int rpos2;
  1425. while (offset < len &&
  1426. (((rpos = r.match(result, offset, &rlen)) >= 0) ||
  1427. ((rpos2 = r2.match(result, offset, &rlen2)) >= 0) )) {
  1428. int slen;
  1429. CTraceItem ci;
  1430. int rofs = (rpos >= 0) ? rpos : rpos2;
  1431. int alen = (rpos >= 0) ? rlen : rlen2;
  1432. offset = rofs + alen;
  1433. sub1.match(result, rofs, &slen);
  1434. rofs += slen;
  1435. sub2.match(result, rofs, &slen);
  1436. ci.setLevel(result.mid(rofs, slen));
  1437. rofs += slen;
  1438. sub1.match(result, rofs, &slen);
  1439. rofs += slen;
  1440. sub4.match(result, rofs, &slen);
  1441. ci.setFunction(result.mid(rofs, slen));
  1442. rofs += slen;
  1443. if (rpos >= 0) {
  1444. sub5.match(result, rofs, &slen);
  1445. ci.setOffset(result.mid(rofs, slen));
  1446. rofs += slen;
  1447. } else
  1448. ci.setOffset("");
  1449. sub6.match(result, rofs, &slen);
  1450. rofs += slen;
  1451. sub7.match(result, rofs, &slen);
  1452. ci.setAddress(result.mid(rofs, slen));
  1453. rofs += slen;
  1454. list.append(ci);
  1455. }
  1456. #endif // !QT >= 3.0
  1457. #endif // !USE_REGEX
  1458. }
  1459. return list;
  1460. }
  1461. CLowcoreList
  1462. QLcrashDoc::getTraceLowcore(const QString& addr)
  1463. {
  1464. CLowcoreList list;
  1465. QString result;
  1466. bool ret = oChildManager->command("trace " + addr, result);
  1467. if (ret) {
  1468. int offset;
  1469. const int len = result.length();
  1470. // check for lowcore info
  1471. if ((offset = result.find("LOWCORE INFO")) != -1) {
  1472. while (offset < len && result[offset].latin1() != '-') {
  1473. offset++;
  1474. }
  1475. QString token;
  1476. pair<QString, QStringList> p;
  1477. while (offset < len) {
  1478. offset = offset + getTraceLowcoreToken(result.latin1() + offset, token);
  1479. if (token[0].latin1() == '-') { // new section
  1480. if (!p.first.isEmpty()) {
  1481. list.append(p);
  1482. }
  1483. p.first = token;
  1484. p.second.clear();
  1485. }
  1486. else { // normal token
  1487. if (token.left(5) == "STACK" || token.at(1).latin1() == '=') {
  1488. break;
  1489. }
  1490. p.second.append(token);
  1491. }
  1492. }
  1493. if (!p.first.isEmpty()) {
  1494. list.append(p);
  1495. }
  1496. }
  1497. }
  1498. return list;
  1499. }
  1500. int
  1501. QLcrashDoc::getTraceLowcoreToken(const char* str, QString& ret)
  1502. {
  1503. bool label = false;
  1504. const char* cptr = str;
  1505. while (*cptr != 0 && (*cptr == ' ' || *cptr == '\t' || *cptr == '\n')) {
  1506. cptr++;
  1507. }
  1508. if (*cptr == '-') {
  1509. label = true;
  1510. ret = "-";
  1511. cptr++;
  1512. }
  1513. else {
  1514. ret = "";
  1515. }
  1516. while (*cptr != 0 && *cptr != (label ? ':' : ' ') && *cptr != '\n') {
  1517. while (*cptr != 0 && *cptr == ' ' && *(cptr-1) == ' ') {
  1518. cptr++;
  1519. }
  1520. while (*cptr != 0 && *cptr == '\n') {
  1521. cptr++;
  1522. }
  1523. if (label && *cptr == ':') {
  1524. cptr++;
  1525. break;
  1526. }
  1527. ret += *cptr++;
  1528. }
  1529. if (label && *cptr == ':') {
  1530. cptr++;
  1531. }
  1532. if (ret.at(ret.length() - 1).latin1() == ':') {
  1533. ret.truncate(ret.length() - 1);
  1534. }
  1535. if (ret.at(ret.length() - 1).latin1() == ' ') {
  1536. ret.truncate(ret.length() - 1);
  1537. }
  1538. return cptr - str;
  1539. }
  1540. QValueList<CTaskItem>
  1541. QLcrashDoc::getTaskList()
  1542. {
  1543. QValueList<CTaskItem> list;
  1544. QString result;
  1545. bool ret = oChildManager->command("task", result);
  1546. if (ret) {
  1547. // skip header
  1548. int offset = 0, len = result.length();
  1549. while (offset < len && !isdigit(result[offset].latin1())) {
  1550. offset++;
  1551. }
  1552. #ifdef USE_REGEX
  1553. regex_t reg;
  1554. regmatch_t sub[6];
  1555. ret = regcomp(
  1556. &reg,
  1557. "(0x[a-z0-9]+)[ \t]+" // ADDR
  1558. "[0-9]+[ \t]+" // UID
  1559. "([0-9]+)[ \t]+" // PID
  1560. "[0-9]+[ \t]+" // PPID
  1561. "([0-9]+)[ \t]+" // STATE
  1562. "0[x0-9]*[ \t]+" // FLAGS
  1563. "(-|[0-9]+)[ \t]+" // CPU
  1564. "(.+)\n", // NAME
  1565. REG_EXTENDED | REG_NEWLINE
  1566. );
  1567. assert(!ret);
  1568. // match line by line
  1569. while (offset < len && regexec(&reg, result.latin1() + offset, 6, sub, 0) == 0) {
  1570. QString part;
  1571. CTaskItem ti;
  1572. part = result.mid(offset + sub[1].rm_so, sub[1].rm_eo - sub[1].rm_so);
  1573. ti.setAddress(part);
  1574. part = result.mid(offset + sub[2].rm_so, sub[2].rm_eo - sub[2].rm_so);
  1575. ti.setPid(part);
  1576. part = result.mid(offset + sub[3].rm_so, sub[3].rm_eo - sub[3].rm_so);
  1577. ti.setStatus(part);
  1578. part = result.mid(offset + sub[4].rm_so, sub[4].rm_eo - sub[4].rm_so);
  1579. ti.setCpu(part);
  1580. part = result.mid(offset + sub[5].rm_so, sub[5].rm_eo - sub[5].rm_so);
  1581. ti.setName(part);
  1582. offset = offset + sub[0].rm_eo;
  1583. list.append(ti);
  1584. }
  1585. regfree(&reg);
  1586. #else
  1587. #if QT_VERSION >= 300
  1588. #warning QT3 QRegExp stuff is yet untested
  1589. QRegExp r(
  1590. "(0x[a-z0-9]+)[ \t]+" // ADDR
  1591. "[0-9]+[ \t]+" // UID
  1592. "([0-9]+)[ \t]+" // PID
  1593. "[0-9]+[ \t]+" // PPID
  1594. "([0-9]+)[ \t]+" // STATE
  1595. "0[x0-9]*[ \t]+" // FLAGS
  1596. "(-|[0-9]+)[ \t]+" // CPU
  1597. "([^\\n]+)\\n" // NAME
  1598. );
  1599. while (offset < len && (r.search(result, offset) >= 0)) {
  1600. CTaskItem ti;
  1601. ti.setAddress(r.cap(1));
  1602. ti.setPid(r.cap(2));
  1603. ti.setStatus(r.cap(3));
  1604. ti.setCpu(r.cap(4));
  1605. ti.setName(r.cap(5));
  1606. offset += r.matchedLength();
  1607. list.append(ti);
  1608. }
  1609. #else
  1610. QRegExp r(
  1611. "0x[a-z0-9]+[ \t]+" // ADDR
  1612. "[0-9]+[ \t]+" // UID
  1613. "[0-9]+[ \t]+" // PID
  1614. "[0-9]+[ \t]+" // PPID
  1615. "[0-9]+[ \t]+" // STATE
  1616. "0[x0-9]*[ \t]+" // FLAGS
  1617. "[0-9-]+[ \t]+" // CPU
  1618. "[^\\n]+\\n" // NAME
  1619. );
  1620. QRegExp sub1("0x[a-z0-9]+"); // cap
  1621. QRegExp sub2("[ \t]+[0-9]+[ \t]+");
  1622. QRegExp sub3("[0-9]+"); // cap
  1623. // QRegExp sub4 == sub2;
  1624. // QRegExp sub5 == sub3; // cap
  1625. QRegExp sub6("[ \t]+0[x0-9]*[ \t]+");
  1626. QRegExp sub7("[0-9-]+"); // cap
  1627. QRegExp sub8("[ \t]+");
  1628. QRegExp sub9("[^\\n]+"); // cap
  1629. int rlen;
  1630. int rpos;
  1631. while (offset < len && ((rpos = r.match(result, offset, &rlen)) >= 0)) {
  1632. int slen;
  1633. CTaskItem ti;
  1634. sub1.match(result, rpos, &slen);
  1635. ti.setAddress(result.mid(rpos, slen));
  1636. rpos += slen;
  1637. sub2.match(result, rpos, &slen);
  1638. rpos += slen;
  1639. sub3.match(result, rpos, &slen);
  1640. ti.setPid(result.mid(rpos, slen));
  1641. rpos += slen;
  1642. sub2.match(result, rpos, &slen);
  1643. rpos += slen;
  1644. sub3.match(result, rpos, &slen);
  1645. ti.setStatus(result.mid(rpos, slen));
  1646. rpos += slen;
  1647. sub6.match(result, rpos, &slen);
  1648. rpos += slen;
  1649. sub7.match(result, rpos, &slen);
  1650. ti.setCpu(result.mid(rpos, slen));
  1651. rpos += slen;
  1652. sub8.match(result, rpos, &slen);
  1653. rpos += slen;
  1654. sub9.match(result, rpos, &slen);
  1655. ti.setName(result.mid(rpos, slen));
  1656. rpos += slen;
  1657. offset += rlen;
  1658. list.append(ti);
  1659. }
  1660. #endif // !QT >= 3.0
  1661. #endif // !USE_REGEX
  1662. }
  1663. return list;
  1664. }
  1665. QValueList<CSymtabItem>
  1666. QLcrashDoc::getGlobalSymbols()
  1667. {
  1668. QValueList<CSymtabItem> list;
  1669. QString result;
  1670. int new_symtab=0;
  1671. bool ret;
  1672. ret = oChildManager->command("symtab -f -l", result);
  1673. if(strncmp(result, "Argument", 8) == 0){
  1674. // lkcdutils 4.2
  1675. ret = oChildManager->command("symtab -t -l", result);
  1676. new_symtab=1;
  1677. }
  1678. if (ret) {
  1679. int offset = 0;
  1680. const int len = result.length();
  1681. const char* cptr = result.latin1();
  1682. while (offset < len) {
  1683. CSymtabItem item;
  1684. QString part;
  1685. if(new_symtab){
  1686. // A new line...
  1687. // ignore leading spaces
  1688. offset += strspn(cptr + offset, " \t");
  1689. // Address
  1690. size_t pos = strcspn(cptr + offset, " \t");
  1691. part = result.mid(offset, pos);
  1692. // validate line
  1693. if (part.left(2) != "0x") {
  1694. offset += strcspn(cptr + offset, "\n") + 1;
  1695. continue;
  1696. }
  1697. offset += pos;
  1698. item.setAddress(part);
  1699. offset += strspn(cptr + offset, " \t");
  1700. // Type
  1701. pos = strcspn(cptr + offset, " \n");
  1702. part = result.mid(offset, pos);
  1703. offset += pos;
  1704. item.setType(part);
  1705. offset += strspn(cptr + offset, " \t");
  1706. // Name
  1707. pos = strcspn(cptr + offset, " \t");
  1708. part = result.mid(offset, pos);
  1709. offset += pos;
  1710. item.setName(part);
  1711. list.append(item);
  1712. offset += strcspn(cptr + offset, "\n") + 1;
  1713. } else {
  1714. // A new line...
  1715. // ignore leading spaces
  1716. offset += strspn(cptr + offset, " \t");
  1717. // Address
  1718. size_t pos = strcspn(cptr + offset, " \n");
  1719. part = result.mid(offset, pos);
  1720. // validate line
  1721. if (part.left(2) != "0x") {
  1722. offset += strcspn(cptr + offset, "\n") + 1;
  1723. continue;
  1724. }
  1725. offset += pos;
  1726. item.setAddress(part);
  1727. offset += strspn(cptr + offset, " \t");
  1728. // A digit
  1729. pos = strcspn(cptr + offset, " \n");
  1730. offset += pos;
  1731. offset += strspn(cptr + offset, " \t");
  1732. // Type
  1733. pos = strcspn(cptr + offset, " \n");
  1734. part = result.mid(offset, pos);
  1735. offset += pos;
  1736. item.setType(part);
  1737. offset += strspn(cptr + offset, " \t");
  1738. // Name
  1739. pos = strcspn(cptr + offset, " \n");
  1740. part = result.mid(offset, pos);
  1741. offset += pos;
  1742. item.setName(part);
  1743. list.append(item);
  1744. offset += strspn(cptr + offset, " \t\n");
  1745. }
  1746. }
  1747. }
  1748. return list;
  1749. }
  1750. QString
  1751. QLcrashDoc::getLcrashHelp()
  1752. {
  1753. QString str;
  1754. bool ret = oChildManager->command("help", str);
  1755. return ret ? str : QString::null;
  1756. }