PageRenderTime 61ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/lkcd-6.1.0/lkcdutils/qlcrash/qlcrash/qlcrashdoc.cpp

#
C++ | 2026 lines | 1622 code | 288 blank | 116 comment | 430 complexity | 951b5eacf6591f4f6f229148696a3e10 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, LGPL-2.1, LGPL-2.0
  1. /*-*-c++-*-
  2. * $Id: qlcrashdoc.cpp 1079 2004-10-22 19:59:34Z troyhebe $
  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. CListView*
  681. QLcrashDoc::getWalk(const QString& name, const QString& addr, const QString& type)
  682. {
  683. bool ret;
  684. QString result;
  685. // determine if `name' is a list_head
  686. ret = oChildManager->command("whatis " + type + "." + name, result);
  687. if (ret) {
  688. if (result.left(16) == "struct list_head") {
  689. return getListHead(name, addr, type);
  690. }
  691. }
  692. else {
  693. printErr(result);
  694. return 0;
  695. }
  696. ret = oChildManager->command("print ((" + type + "*)" + addr + ")->" + name, result);
  697. if (ret) {
  698. removeTypeInfo(result);
  699. // remove trailing prompt
  700. if (result.right(CMD_PROMPT_LEN) == CMD_PROMPT) {
  701. result.truncate(result.length() - CMD_PROMPT_LEN);
  702. }
  703. result = result.stripWhiteSpace();
  704. CListView* lv = new CListView(0);
  705. lv->addColumn(tr("Name"));
  706. lv->addColumn(tr("Value"));
  707. lv->addColumn(tr("Type"));
  708. lv->setMinimumSize(200, 100);
  709. lv->setSorting(-1);
  710. StructViewItem* svi = new StructViewItem(lv);
  711. StructViewItem* after = 0;
  712. svi->setText(0, type + "." + name);
  713. svi->setText(1, addr);
  714. svi->setType(type);
  715. svi->setPixmapType(Array);
  716. int i = 0;
  717. Avl<QString> aset;
  718. do {
  719. aset.insert(result);
  720. StructViewItem* svch = after ? new StructViewItem(svi, after) : new StructViewItem(svi);
  721. after = svch;
  722. svch->setText(0, QString::number(i++));
  723. svch->setText(1, result);
  724. svch->setText(2, type + "*");
  725. svch->setType(type + "*");
  726. svch->setPixmapType(Pointer);
  727. // avoid infinite recursion
  728. if (i > WALKMAX) {
  729. sigErrToConsole(0, tr("Walk has reached WALKMAX (%1)").arg(QString::number(WALKMAX)));
  730. break;
  731. }
  732. ret = oChildManager->command("print ((" + type + "*)" + result + ")->" + name, result);
  733. if(ret){
  734. removeTypeInfo(result);
  735. }
  736. // remove trailing prompt
  737. if (ret && result.right(CMD_PROMPT_LEN) == CMD_PROMPT) {
  738. result.truncate(result.length() - CMD_PROMPT_LEN);
  739. }
  740. result = result.stripWhiteSpace();
  741. } while (ret && result != "0x0" && result[0].latin1() != '(' && !aset.search(result));
  742. svi->setOpen(true);
  743. lv->setCaption("walk:" + type + "." + name + "@" + addr);
  744. return lv;
  745. }
  746. return 0;
  747. }
  748. CListView*
  749. QLcrashDoc::getListHead(const QString& name, const QString& addr, const QString& type)
  750. {
  751. QString result;
  752. CListView* tree = 0;
  753. bool ret = oChildManager->command("walk -h n -t " + type + " " + name + " " + addr, result);
  754. if (ret) {
  755. QList<QString>* list = new QList<QString>;
  756. list->setAutoDelete(true);
  757. // create a list of addresses using the first column
  758. const int len = result.length();
  759. for (int i = 0; i < len; i++) {
  760. // ignore white space
  761. while (i < len && (result[i].latin1() == ' ' || result[i].latin1() == '\t'))
  762. i++;
  763. if (isdigit(result[i].latin1())) {
  764. int s = i++;
  765. while (i < len && isalnum(result[i].latin1()))
  766. i++;
  767. list->append(new QString(result.mid(s, i - s)));
  768. }
  769. // ignore the rest of the line
  770. while (i < len && result[i].latin1() != '\n')
  771. i++;
  772. }
  773. // lreate a list view
  774. CListView* lv = new CListView(0);
  775. lv->addColumn(tr("Name"));
  776. lv->addColumn(tr("Value"));
  777. lv->addColumn(tr("Type"));
  778. lv->setMinimumSize(200, 100);
  779. lv->setSorting(-1);
  780. StructViewItem* svi = new StructViewItem(lv);
  781. StructViewItem* after = 0;
  782. svi->setText(0, type + "." + name);
  783. svi->setText(1, addr);
  784. svi->setType(type);
  785. svi->setPixmapType(Array);
  786. QString* walker = list->first();
  787. int n = 0;
  788. while (walker != 0) {
  789. if (walker->length() > 1) {
  790. StructViewItem* svch = after ? new StructViewItem(svi, after) : new StructViewItem(svi);
  791. after = svch;
  792. svch->setText(0, QString::number(n++));
  793. svch->setText(1, *walker);
  794. svch->setText(2, type + "*");
  795. svch->setType(type + "*");
  796. svch->setPixmapType(Pointer);
  797. }
  798. walker = list->next();
  799. }
  800. delete list;
  801. svi->setOpen(true);
  802. lv->setCaption("walk:" + type + "." + name + "@" + addr);
  803. tree = lv;
  804. }
  805. return tree;
  806. }
  807. void
  808. QLcrashDoc::slotStderrFromChild(QString str)
  809. {
  810. emit sigErrToConsole(0, str);
  811. }
  812. void
  813. QLcrashDoc::slotStdoutFromChild(QString str)
  814. {
  815. if (oWaitForInit) {
  816. if (str.right(CMD_PROMPT_LEN) == CMD_PROMPT) {
  817. oWaitForInit = false;
  818. lcrashIsReady = true;
  819. oInitialTimer->start(1000, true);
  820. // emit sigLCrashReady();
  821. // Initial newline
  822. emit sigToConsole(0, "\n");
  823. }
  824. }
  825. if (oGraph == false) {
  826. emit sigToConsole(0, str);
  827. }
  828. }
  829. void
  830. QLcrashDoc::printTypeInfo(const QString& type, const QString& name)
  831. {
  832. if (type == "" || type == "?") {
  833. sigErrToConsole(0, tr("Could not get type info") + "\n");
  834. }
  835. else {
  836. int size = sizeinfo(type, name);
  837. if (size > 0) {
  838. emit sigToConsole(0, QString("\n") + tr("Type") + ": " + type + "\n");
  839. emit sigToConsole(0, tr("sizeof") + ": " + QString::number(size) + " Bytes\n");
  840. }
  841. else {
  842. sigErrToConsole(0, tr("Could not get type info") + "\n");
  843. }
  844. }
  845. emit sigToConsole(0, CMD_PROMPT);
  846. }
  847. void
  848. QLcrashDoc::printWhatis(const QString& type, const QString& name)
  849. {
  850. if (type.length() == 0 || type == "?") {
  851. sigErrToConsole(0, tr("'whatis' failed") + "\n");
  852. }
  853. else {
  854. QString result;
  855. bool w = oChildManager->command("whatis " + type, result);
  856. if (w) {
  857. emit sigToConsole(0, type + " = " + result + "\n");
  858. }
  859. else {
  860. w = oChildManager->command("whatis " + name, result);
  861. if (w) {
  862. emit sigToConsole(0, name + " = " + result + "\n");
  863. }
  864. else {
  865. emit sigErrToConsole(0, tr("'whatis' failed") + ".\n");
  866. }
  867. }
  868. }
  869. emit sigToConsole(0, CMD_PROMPT);
  870. }
  871. void
  872. QLcrashDoc::printTrace(const QString& addr)
  873. {
  874. QString result;
  875. bool w = oChildManager->command(QString("trace") + " " + addr, result);
  876. if (w) {
  877. sigToConsole(0, (QString) "\n" + result + "\n");
  878. }
  879. emit sigToConsole(0, CMD_PROMPT);
  880. }
  881. int
  882. QLcrashDoc::sizeinfo(const QString& type, const QString& name)
  883. {
  884. // a pointer has always the same size
  885. if (type.right(1) == "*") {
  886. return targetWordSize();
  887. }
  888. // compare types with builtin types
  889. Avl<QString> set;
  890. QStringList list = QStringList::split(' ', type);
  891. for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
  892. set.insert(*it);
  893. }
  894. // check for 'long long'
  895. Avl<QString>::iterator ait = set.find("long");
  896. if (ait != set.end()) {
  897. // is there a second 'long' ?
  898. if (++ait != set.end() && *ait == "long") {
  899. return 8;
  900. }
  901. return targetWordSize();
  902. }
  903. if (set.search("int")) {
  904. return 4;
  905. }
  906. if (set.search("short")) {
  907. return 2;
  908. }
  909. if (set.search("char")) {
  910. return 1;
  911. }
  912. #ifndef WIN32
  913. #warning "This could become a problem..."
  914. #endif
  915. if (set.search("double")) {
  916. return sizeof(double);
  917. }
  918. if (set.search("float")) {
  919. return sizeof(float);
  920. }
  921. // not a builtin type
  922. QString result;
  923. bool ret = oChildManager->command("sizeof " + type, result);
  924. if (!ret) { // try 'whatis' followed by 'sizeof'
  925. ret = oChildManager->command("whatis (" + type + ")", result);
  926. if (ret) {
  927. ret = oChildManager->command("sizeof " + result, result);
  928. }
  929. if (!ret && name.length() > 0) { // try attribute name
  930. ret = oChildManager->command("sizeof " + name, result);
  931. }
  932. }
  933. if (ret) {
  934. QString num = "";
  935. int i, len = result.length(),match_len;
  936. // skip to colon
  937. QRegExp r(": *[0-9]");
  938. i=r.match(result,0,&match_len);
  939. i+=match_len -1;
  940. // copy number digit by digit
  941. for (; i < len; i++) {
  942. char ch = result.at(i).latin1();
  943. if (!isdigit(ch)) {
  944. break;
  945. }
  946. num.append(ch);
  947. }
  948. int val = num.toInt(&ret);
  949. return ret ? val : 0;
  950. }
  951. else {
  952. sigErrToConsole(0, QString("\n") + tr("Size of `%1' unknown").arg(type) + "\n");
  953. }
  954. return 0;
  955. }
  956. void
  957. QLcrashDoc::print(const QString& str)
  958. {
  959. sigToConsole(0, str + "\n" + CMD_PROMPT);
  960. }
  961. void
  962. QLcrashDoc::printErr(const QString& str)
  963. {
  964. sigErrToConsole(0, str + "\n" + CMD_PROMPT);
  965. }
  966. QString
  967. QLcrashDoc::printFormat() const
  968. {
  969. int idx = oConfigManager->item(CFG_GRP_GRAPH, CFG_ATT_GRAPH_PRINTFORMAT, 0);
  970. if (idx > 0) {
  971. switch (idx) {
  972. case 1:
  973. return " -x ";
  974. case 2:
  975. return " -d ";
  976. case 3:
  977. return " -o ";
  978. case 4:
  979. return " -b ";
  980. default:
  981. return " ";
  982. }
  983. }
  984. return " ";
  985. }
  986. const unsigned char*
  987. QLcrashDoc::getDump(const QString& addr)
  988. {
  989. if (oWaitForInit) {
  990. return 0;
  991. }
  992. unsigned char* cptr = oDumpCache->find(addr);
  993. if (cptr == 0) {
  994. QString sAddr = QString("0x") + addr;
  995. QString result;
  996. bool ret = oChildManager->command("dump -B " + sAddr + " 16", result);
  997. if (ret) {
  998. cptr = new unsigned char[16];
  999. oDumpCache->insert(addr, cptr);
  1000. int len = result.length();
  1001. int i;
  1002. // skip to the first colon
  1003. for (i = 0; i < len && result.at(i).latin1() != ':'; i++) { /* empty */ }
  1004. i += 2;
  1005. unsigned char ch;
  1006. int idx = 0, s = -1;
  1007. while (i < len && (ch = result.at(i).latin1()) != ':') {
  1008. i++;
  1009. if (ch == ' ') {
  1010. assert(idx < 16);
  1011. cptr[idx++] = s;
  1012. s = -1;
  1013. continue;
  1014. }
  1015. s = (s == -1) ? hexCharToInt(ch) * 16 : s + hexCharToInt(ch);
  1016. }
  1017. }
  1018. }
  1019. return cptr;
  1020. }
  1021. int
  1022. QLcrashDoc::targetSetup()
  1023. {
  1024. QString result;
  1025. bool ret = oChildManager->command("info -s endian", result);
  1026. if (ret) {
  1027. if(result.mid(0,6) == "little"){
  1028. oTargetEndian=little;
  1029. } else if(result.mid(0,3) == "big") {
  1030. oTargetEndian=big;
  1031. } else {
  1032. cerr << "QLcrashDoc::targetLittleEndian: info -s failed\n";
  1033. oTargetEndian=unknown;
  1034. }
  1035. } else {
  1036. cerr << "QLcrashDoc::targetLittleEndian: info -s failed\n";
  1037. oTargetEndian=unknown;
  1038. }
  1039. ret = oChildManager->command("info -s psize", result);
  1040. if (ret) {
  1041. if(result.mid(0,2) == "32"){
  1042. oTargetWordSize=4;
  1043. } else if(result.mid(0,2) == "64"){
  1044. oTargetWordSize=8;
  1045. } else {
  1046. cerr << "QLcrashDoc::targetWordSize: info -s psize returned '" << result << "'\n";
  1047. oTargetWordSize=-1;
  1048. }
  1049. } else {
  1050. cerr << "QLcrashDoc::targetWordSize: info -s psize failed\n";
  1051. oTargetWordSize=-1;
  1052. }
  1053. return 0;
  1054. }
  1055. bool
  1056. QLcrashDoc::targetLittleEndian() const
  1057. {
  1058. if(oTargetEndian == little)
  1059. return true;
  1060. else
  1061. return false;
  1062. }
  1063. int
  1064. QLcrashDoc::targetWordSize() const
  1065. {
  1066. if(oTargetWordSize == -1)
  1067. return sizeof(long);
  1068. else
  1069. return oTargetWordSize;
  1070. }
  1071. QStringList*
  1072. QLcrashDoc::s390AvailableLogs()
  1073. {
  1074. QStringList* list = new QStringList;
  1075. QString result;
  1076. bool ret = oChildManager->command("s390dbf", result);
  1077. if (ret) {
  1078. *list = QStringList::split('\n', result);
  1079. int count = list->count();
  1080. if (count > 2) {
  1081. QStringList::Iterator it = list->begin();
  1082. it = list->remove(it);
  1083. it = list->remove(it);
  1084. for (int i = 2; i < count - 1; i++) {
  1085. (*it) = (*it).simplifyWhiteSpace();
  1086. (*it) = (*it).mid(2);
  1087. ++it;
  1088. }
  1089. list->remove(it);
  1090. }
  1091. }
  1092. return list;
  1093. }
  1094. QStringList*
  1095. QLcrashDoc::s390AvailableViews(const QString& log)
  1096. {
  1097. QStringList* list = new QStringList;
  1098. QString result;
  1099. bool ret = oChildManager->command("s390dbf " + log, result);
  1100. if (ret) {
  1101. *list = QStringList::split('\n', result);
  1102. int count = list->count();
  1103. if (count > 3) {
  1104. QStringList::Iterator it = list->begin();
  1105. it = list->remove(it);
  1106. it = list->remove(it);
  1107. for (int i = 2; i < count - 2; i++) {
  1108. (*it) = (*it).simplifyWhiteSpace();
  1109. // (*it) = QStringList::split(' ', (*it).mid(2)).first();
  1110. (*it) = (*it).mid(2);
  1111. ++it;
  1112. }
  1113. it = list->remove(it);
  1114. list->remove(it);
  1115. }
  1116. }
  1117. return list;
  1118. }
  1119. QString
  1120. QLcrashDoc::s390dbfText(const QString& log, const QString& view)
  1121. {
  1122. QString result;
  1123. oChildManager->command("s390dbf " + log + " " + view, result);
  1124. // remove trailing newline and prompt
  1125. if (result.right(CMD_PROMPT_LEN) == CMD_PROMPT) {
  1126. result.truncate(result.length() - CMD_PROMPT_LEN);
  1127. }
  1128. while (!result.isEmpty() && result.right(1) == "\n") {
  1129. result.truncate(result.length() - 1);
  1130. }
  1131. return result;
  1132. }
  1133. void
  1134. QLcrashDoc::s390dbfSaveToFile(const QString& log, const QString& view, const QString& file)
  1135. {
  1136. QString result;
  1137. bool ret = oChildManager->command("s390dbf -w " + file + " " + log + " " + view, result);
  1138. if (!ret) {
  1139. emit printErr(result);
  1140. }
  1141. }
  1142. bool
  1143. QLcrashDoc::haveDebugFeature()
  1144. {
  1145. if (oWaitForInit) {
  1146. cerr << "QLcrashDoc::haveDebugFeature() called during initialization phase." << endl;
  1147. return false;
  1148. }
  1149. if (oS390dbf == -1) {
  1150. QString result;
  1151. bool ret = oChildManager->command("s390dbf", result);
  1152. oS390dbf = ret ? 1 : 0;
  1153. }
  1154. return oS390dbf;
  1155. }
  1156. QString
  1157. QLcrashDoc::helpHomeURL()
  1158. {
  1159. #ifdef WIN32
  1160. #ifdef _DEBUG
  1161. return QString("file:/") + execdir() + "/../../Doc/Manual/index.html";
  1162. #else
  1163. return QString("file:/") + execdir() + "/Manual/index.html";
  1164. #endif
  1165. #else
  1166. return "file:/" DOCDIR "/index.html";
  1167. #endif
  1168. }
  1169. QString
  1170. QLcrashDoc::lastSaveDir() const
  1171. {
  1172. return oLastSaveDir;
  1173. }
  1174. void
  1175. QLcrashDoc::setLastSaveDir(const QString& lsd)
  1176. {
  1177. oLastSaveDir = lsd;
  1178. }
  1179. QString
  1180. QLcrashDoc::getTypeFromExpression(const QString& expr) const
  1181. {
  1182. int len = expr.length();
  1183. int i = expr.find("print");
  1184. int count = 0;
  1185. QString type;
  1186. if (i != -1) {
  1187. i += 5;
  1188. }
  1189. else {
  1190. i = 0;
  1191. }
  1192. for (; i < len; i++) {
  1193. if (expr[i].latin1() != ' ') {
  1194. break;
  1195. }
  1196. }
  1197. for (; i < len; i++) {
  1198. if (expr[i].latin1() == '*') {
  1199. count--;
  1200. }
  1201. else {
  1202. break;
  1203. }
  1204. }
  1205. for (; i < len; i++) {
  1206. if (expr[i].latin1() == '(') {
  1207. break;
  1208. }
  1209. }
  1210. while (i < len && !isalpha(expr[i].latin1())) {
  1211. i++;
  1212. }
  1213. char ch;
  1214. int start = i;
  1215. while (i < len && (isalpha((ch = expr[i].latin1()))||ch=='_'||ch==' '|| (isdigit(ch) && (start < i)) )) {
  1216. type += ch;
  1217. i++;
  1218. }
  1219. for (; i < len; i++) {
  1220. ch = expr[i].latin1();
  1221. switch (ch) {
  1222. case '*':
  1223. count++;
  1224. break;
  1225. case ')':
  1226. i = len;
  1227. break;
  1228. default:
  1229. continue;
  1230. }
  1231. }
  1232. for (i = 0; i < count; i++) {
  1233. type += '*';
  1234. }
  1235. return (count >= 0) ? type : QString::null;
  1236. }
  1237. QString
  1238. QLcrashDoc::getAddressFromExpression(const QString& expr) const
  1239. {
  1240. QString ret;
  1241. int pos = expr.find("0x");
  1242. if (pos >= 0) {
  1243. const int len = expr.length();
  1244. pos += 2;
  1245. ret = "0x";
  1246. while (pos < len && isxdigit(expr[pos].latin1())) {
  1247. ret += expr[pos];
  1248. pos++;
  1249. }
  1250. }
  1251. return ret;
  1252. }
  1253. QValueList<CDisassemble>
  1254. QLcrashDoc::getDisassemble(const QString& fkt)
  1255. {
  1256. QValueList<CDisassemble> list;
  1257. QString result;
  1258. bool ret = oChildManager->command("dis -F " + fkt, result);
  1259. if (ret) {
  1260. #ifdef USE_REGEX
  1261. regex_t reg;
  1262. regmatch_t sub[4];
  1263. ret = regcomp(
  1264. &reg,
  1265. "(0x[0-9a-f]+)[ \t]*(<[^>]+>):[ \t]*(.+)\n",
  1266. REG_EXTENDED | REG_NEWLINE
  1267. );
  1268. assert(!ret);
  1269. int offset = 0, len = result.length();
  1270. while (offset < len && regexec(&reg, result.latin1() + offset, 4, sub, 0) == 0) {
  1271. QString part;
  1272. CDisassemble cd;
  1273. part = result.mid(offset + sub[1].rm_so, sub[1].rm_eo - sub[1].rm_so);
  1274. cd.setAddr(part.simplifyWhiteSpace());
  1275. part = result.mid(offset + sub[2].rm_so, sub[2].rm_eo - sub[2].rm_so);
  1276. cd.setOffset(part.simplifyWhiteSpace());
  1277. part = result.mid(offset + sub[3].rm_so, sub[3].rm_eo - sub[3].rm_so);
  1278. cd.setMnemonic(part.simplifyWhiteSpace());
  1279. list.append(cd);
  1280. offset = offset + sub[0].rm_eo;
  1281. }
  1282. regfree(&reg);
  1283. #else
  1284. #if QT_VERSION >= 300
  1285. // New QT 3.0
  1286. QRegExp r("(0x[0-9a-f]+)[ \t]*(<[^>]+>):[ \t]*([^\\n]+)\n");
  1287. int offset = 0, len = result.length();
  1288. while (offset < len && (r.search(result, offset) >= 0)) {
  1289. CDisassemble cd;
  1290. cd.setAddr(r.cap(1).simplifyWhiteSpace());
  1291. cd.setOffset(r.cap(2).simplifyWhiteSpace());
  1292. cd.setMnemonic(r.cap(3).simplifyWhiteSpace());
  1293. list.append(cd);
  1294. offset += r.matchedLength();
  1295. }
  1296. #else
  1297. // Old QT < 3.0
  1298. QRegExp r("0x[0-9a-f]+[ \t]*<[^>]+>:[ \t]*[^\\n]+\\n");
  1299. QRegExp sub1("0x[0-9a-f]+");
  1300. QRegExp sub2("[ \t]*");
  1301. QRegExp sub3("<[^>]+>");
  1302. QRegExp sub4(":[ \t]*");
  1303. QRegExp sub5("[^\\n]+");
  1304. int offset = 0, len = result.length();
  1305. int rlen;
  1306. int rpos;
  1307. while (offset < len && ((rpos = r.match(result, offset, &rlen)) >= 0)) {
  1308. int slen;
  1309. CDisassemble cd;
  1310. sub1.match(result, rpos, &slen);
  1311. cd.setAddr(result.mid(rpos, slen).simplifyWhiteSpace());
  1312. rpos += slen;
  1313. sub2.match(result, rpos, &slen);
  1314. rpos += slen;
  1315. sub3.match(result, rpos, &slen);
  1316. cd.setOffset(result.mid(rpos, slen).simplifyWhiteSpace());
  1317. rpos += slen;
  1318. sub4.match(result, rpos, &slen);
  1319. rpos += slen;
  1320. sub5.match(result, rpos, &slen);
  1321. cd.setMnemonic(result.mid(rpos, slen).simplifyWhiteSpace());
  1322. list.append(cd);
  1323. offset += rlen;
  1324. }
  1325. #endif // !QT 3.0
  1326. #endif // !USE_REGEX
  1327. }
  1328. return list;
  1329. }
  1330. QValueList<CTraceItem>
  1331. QLcrashDoc::getTrace(const QString& addr)
  1332. {
  1333. QValueList<CTraceItem> list;
  1334. QString result;
  1335. bool ret = oChildManager->command("trace " + addr, result);
  1336. if (ret) {
  1337. int offset = 0, len = result.length();
  1338. // skip header and retrieve task name
  1339. while (offset < len && result[offset].latin1() != '(') {
  1340. offset++;
  1341. }
  1342. QString name;
  1343. offset++;
  1344. while (offset < len && result[offset].latin1() != ')') {
  1345. name.append(result[offset]);
  1346. offset++;
  1347. }
  1348. CTraceItem item;
  1349. item.setFunction(name);
  1350. list.append(item);
  1351. while (offset < len && !isdigit(result[offset].latin1())) {
  1352. offset++;
  1353. }
  1354. #ifdef USE_REGEX
  1355. regex_t reg;
  1356. regmatch_t sub[5];
  1357. ret = regcomp(
  1358. &reg,
  1359. "[ \t]*([0-9]+)[ \t]*([a-zA-Z0-9_]+)(\\+[0-9]+)?[ \t]*\\[(0x[0-9a-zA-F]+)\\][ \t]*\n",
  1360. REG_EXTENDED | REG_NEWLINE
  1361. );
  1362. assert(!ret);
  1363. while (offset < len && regexec(&reg, result.latin1() + offset, 5, sub, 0) == 0) {
  1364. QString part;
  1365. CTraceItem ci;
  1366. part = result.mid(offset + sub[1].rm_so, sub[1].rm_eo - sub[1].rm_so);
  1367. ci.setLevel(part);
  1368. part = result.mid(offset + sub[2].rm_so, sub[2].rm_eo - sub[2].rm_so);
  1369. ci.setFunction(part);
  1370. part = result.mid(offset + sub[3].rm_so, sub[3].rm_eo - sub[3].rm_so);
  1371. ci.setOffset(part);
  1372. part = result.mid(offset + sub[4].rm_so, sub[4].rm_eo - sub[4].rm_so);
  1373. ci.setAddress(part);
  1374. offset = offset + sub[0].rm_eo;
  1375. list.append(ci);
  1376. }
  1377. regfree(&reg);
  1378. #else
  1379. #if QT_VERSION >= 300
  1380. #warning QT3 QRegExp stuff is yet untested
  1381. QRegExp r("[ \t]*([0-9]+)[ \t]*([a-zA-Z0-9_]+)(\\+[0-9]+)?[ \t]*\\[(0x[0-9a-zA-F]+)\\][ \t]*\\n");
  1382. offset = r.search(result,offset);
  1383. while (offset < len && ((offset = r.search(result, offset)) >= 0)) {
  1384. CTraceItem ci;
  1385. ci.setLevel(r.cap(1));
  1386. ci.setFunction(r.cap(2));
  1387. ci.setOffset(r.cap(3));
  1388. ci.setAddress(r.cap(4));
  1389. list.append(ci);
  1390. offset += r.matchedLength();
  1391. }
  1392. #else
  1393. QRegExp r("[ \t]*[0-9]+[ \t]*[a-zA-Z0-9_]+\\+[0-9]+[ \t]*\\[0x[0-9a-zA-F]+\\][ \t]*\\n");
  1394. QRegExp r2("[ \t]*[0-9]+[ \t]*[a-zA-Z0-9_]+[ \t]*\\[0x[0-9a-zA-F]+\\][ \t]*\\n");
  1395. QRegExp sub1("[ \t]*");
  1396. QRegExp sub2("[0-9]+"); // cap
  1397. //QRegExp sub3 = sub1;
  1398. QRegExp sub4("[a-zA-Z0-9_]+"); // cap
  1399. QRegExp sub5("\\+[0-9]+"); // cap
  1400. QRegExp sub6("[ \t]*\\[");
  1401. QRegExp sub7("0x[0-9a-zA-F]+"); // cap
  1402. //QRegExp sub8("\\][ \t]*\\n");
  1403. int rlen;
  1404. int rlen2;
  1405. int rpos;
  1406. int rpos2;
  1407. while (offset < len &&
  1408. (((rpos = r.match(result, offset, &rlen)) >= 0) ||
  1409. ((rpos2 = r2.match(result, offset, &rlen2)) >= 0) )) {
  1410. int slen;
  1411. CTraceItem ci;
  1412. int rofs = (rpos >= 0) ? rpos : rpos2;
  1413. int alen = (rpos >= 0) ? rlen : rlen2;
  1414. offset = rofs + alen;
  1415. sub1.match(result, rofs, &slen);
  1416. rofs += slen;
  1417. sub2.match(result, rofs, &slen);
  1418. ci.setLevel(result.mid(rofs, slen));
  1419. rofs += slen;
  1420. sub1.match(result, rofs, &slen);
  1421. rofs += slen;
  1422. sub4.match(result, rofs, &slen);
  1423. ci.setFunction(result.mid(rofs, slen));
  1424. rofs += slen;
  1425. if (rpos >= 0) {
  1426. sub5.match(result, rofs, &slen);
  1427. ci.setOffset(result.mid(rofs, slen));
  1428. rofs += slen;
  1429. } else
  1430. ci.setOffset("");
  1431. sub6.match(result, rofs, &slen);
  1432. rofs += slen;
  1433. sub7.match(result, rofs, &slen);
  1434. ci.setAddress(result.mid(rofs, slen));
  1435. rofs += slen;
  1436. list.append(ci);
  1437. }
  1438. #endif // !QT >= 3.0
  1439. #endif // !USE_REGEX
  1440. }
  1441. return list;
  1442. }
  1443. CLowcoreList
  1444. QLcrashDoc::getTraceLowcore(const QString& addr)
  1445. {
  1446. CLowcoreList list;
  1447. QString result;
  1448. bool ret = oChildManager->command("trace " + addr, result);
  1449. if (ret) {
  1450. int offset;
  1451. const int len = result.length();
  1452. // check for lowcore info
  1453. if ((offset = result.find("LOWCORE INFO")) != -1) {
  1454. while (offset < len && result[offset].latin1() != '-') {
  1455. offset++;
  1456. }
  1457. QString token;
  1458. pair<QString, QStringList> p;
  1459. while (offset < len) {
  1460. offset = offset + getTraceLowcoreToken(result.latin1() + offset, token);
  1461. if (token[0].latin1() == '-') { // new section
  1462. if (!p.first.isEmpty()) {
  1463. list.append(p);
  1464. }
  1465. p.first = token;
  1466. p.second.clear();
  1467. }
  1468. else { // normal token
  1469. if (token.left(5) == "STACK" || token.at(1).latin1() == '=') {
  1470. break;
  1471. }
  1472. p.second.append(token);
  1473. }
  1474. }
  1475. if (!p.first.isEmpty()) {
  1476. list.append(p);
  1477. }
  1478. }
  1479. }
  1480. return list;
  1481. }
  1482. int
  1483. QLcrashDoc::getTraceLowcoreToken(const char* str, QString& ret)
  1484. {
  1485. bool label = false;
  1486. const char* cptr = str;
  1487. while (*cptr != 0 && (*cptr == ' ' || *cptr == '\t' || *cptr == '\n')) {
  1488. cptr++;
  1489. }
  1490. if (*cptr == '-') {
  1491. label = true;
  1492. ret = "-";
  1493. cptr++;
  1494. }
  1495. else {
  1496. ret = "";
  1497. }
  1498. while (*cptr != 0 && *cptr != (label ? ':' : ' ') && *cptr != '\n') {
  1499. while (*cptr != 0 && *cptr == ' ' && *(cptr-1) == ' ') {
  1500. cptr++;
  1501. }
  1502. while (*cptr != 0 && *cptr == '\n') {
  1503. cptr++;
  1504. }
  1505. if (label && *cptr == ':') {
  1506. cptr++;
  1507. break;
  1508. }
  1509. ret += *cptr++;
  1510. }
  1511. if (label && *cptr == ':') {
  1512. cptr++;
  1513. }
  1514. if (ret.at(ret.length() - 1).latin1() == ':') {
  1515. ret.truncate(ret.length() - 1);
  1516. }
  1517. if (ret.at(ret.length() - 1).latin1() == ' ') {
  1518. ret.truncate(ret.length() - 1);
  1519. }
  1520. return cptr - str;
  1521. }
  1522. QValueList<CTaskItem>
  1523. QLcrashDoc::getTaskList()
  1524. {
  1525. QValueList<CTaskItem> list;
  1526. QString result;
  1527. bool ret = oChildManager->command("task", result);
  1528. if (ret) {
  1529. // skip header
  1530. int offset = 0, len = result.length();
  1531. while (offset < len && !isdigit(result[offset].latin1())) {
  1532. offset++;
  1533. }
  1534. #ifdef USE_REGEX
  1535. regex_t reg;
  1536. regmatch_t sub[6];
  1537. ret = regcomp(
  1538. &reg,
  1539. "(0x[a-z0-9]+)[ \t]+" // ADDR
  1540. "[0-9]+[ \t]+" // UID
  1541. "([0-9]+)[ \t]+" // PID
  1542. "[0-9]+[ \t]+" // PPID
  1543. "([0-9]+)[ \t]+" // STATE
  1544. "0[x0-9]*[ \t]+" // FLAGS
  1545. "(-|[0-9]+)[ \t]+" // CPU
  1546. "(.+)\n", // NAME
  1547. REG_EXTENDED | REG_NEWLINE
  1548. );
  1549. assert(!ret);
  1550. // match line by line
  1551. while (offset < len && regexec(&reg, result.latin1() + offset, 6, sub, 0) == 0) {
  1552. QString part;
  1553. CTaskItem ti;
  1554. part = result.mid(offset + sub[1].rm_so, sub[1].rm_eo - sub[1].rm_so);
  1555. ti.setAddress(part);
  1556. part = result.mid(offset + sub[2].rm_so, sub[2].rm_eo - sub[2].rm_so);
  1557. ti.setPid(part);
  1558. part = result.mid(offset + sub[3].rm_so, sub[3].rm_eo - sub[3].rm_so);
  1559. ti.setStatus(part);
  1560. part = result.mid(offset + sub[4].rm_so, sub[4].rm_eo - sub[4].rm_so);
  1561. ti.setCpu(part);
  1562. part = result.mid(offset + sub[5].rm_so, sub[5].rm_eo - sub[5].rm_so);
  1563. ti.setName(part);
  1564. offset = offset + sub[0].rm_eo;
  1565. list.append(ti);
  1566. }
  1567. regfree(&reg);
  1568. #else
  1569. #if QT_VERSION >= 300
  1570. #warning QT3 QRegExp stuff is yet untested
  1571. QRegExp r(
  1572. "(0x[a-z0-9]+)[ \t]+" // ADDR
  1573. "[0-9]+[ \t]+" // UID
  1574. "([0-9]+)[ \t]+" // PID
  1575. "[0-9]+[ \t]+" // PPID
  1576. "([0-9]+)[ \t]+" // STATE
  1577. "0[x0-9]*[ \t]+" // FLAGS
  1578. "(-|[0-9]+)[ \t]+" // CPU
  1579. "([^\\n]+)\\n" // NAME
  1580. );
  1581. while (offset < len && (r.search(result, offset) >= 0)) {
  1582. CTaskItem ti;
  1583. ti.setAddress(r.cap(1));
  1584. ti.setPid(r.cap(2));
  1585. ti.setStatus(r.cap(3));
  1586. ti.setCpu(r.cap(4));
  1587. ti.setName(r.cap(5));
  1588. offset += r.matchedLength();
  1589. list.append(ti);
  1590. }
  1591. #else
  1592. QRegExp r(
  1593. "0x[a-z0-9]+[ \t]+" // ADDR
  1594. "[0-9]+[ \t]+" // UID
  1595. "[0-9]+[ \t]+" // PID
  1596. "[0-9]+[ \t]+" // PPID
  1597. "[0-9]+[ \t]+" // STATE
  1598. "0[x0-9]*[ \t]+" // FLAGS
  1599. "[0-9-]+[ \t]+" // CPU
  1600. "[^\\n]+\\n" // NAME
  1601. );
  1602. QRegExp sub1("0x[a-z0-9]+"); // cap
  1603. QRegExp sub2("[ \t]+[0-9]+[ \t]+");
  1604. QRegExp sub3("[0-9]+"); // cap
  1605. // QRegExp sub4 == sub2;
  1606. // QRegExp sub5 == sub3; // cap
  1607. QRegExp sub6("[ \t]+0[x0-9]*[ \t]+");
  1608. QRegExp sub7("[0-9-]+"); // cap
  1609. QRegExp sub8("[ \t]+");
  1610. QRegExp sub9("[^\\n]+"); // cap
  1611. int rlen;
  1612. int rpos;
  1613. while (offset < len && ((rpos = r.match(result, offset, &rlen)) >= 0)) {
  1614. int slen;
  1615. CTaskItem ti;
  1616. sub1.match(result, rpos, &slen);
  1617. ti.setAddress(result.mid(rpos, slen));
  1618. rpos += slen;
  1619. sub2.match(result, rpos, &slen);
  1620. rpos += slen;
  1621. sub3.match(result, rpos, &slen);
  1622. ti.setPid(result.mid(rpos, slen));
  1623. rpos += slen;
  1624. sub2.match(result, rpos, &slen);
  1625. rpos += slen;
  1626. sub3.match(result, rpos, &slen);
  1627. ti.setStatus(result.mid(rpos, slen));
  1628. rpos += slen;
  1629. sub6.match(result, rpos, &slen);
  1630. rpos += slen;
  1631. sub7.match(result, rpos, &slen);
  1632. ti.setCpu(result.mid(rpos, slen));
  1633. rpos += slen;
  1634. sub8.match(result, rpos, &slen);
  1635. rpos += slen;
  1636. sub9.match(result, rpos, &slen);
  1637. ti.setName(result.mid(rpos, slen));
  1638. rpos += slen;
  1639. offset += rlen;
  1640. list.append(ti);
  1641. }
  1642. #endif // !QT >= 3.0
  1643. #endif // !USE_REGEX
  1644. }
  1645. return list;
  1646. }
  1647. QValueList<CSymtabItem>
  1648. QLcrashDoc::getGlobalSymbols()
  1649. {
  1650. QValueList<CSymtabItem> list;
  1651. QString result;
  1652. int new_symtab=0;
  1653. bool ret;
  1654. ret = oChildManager->command("symtab -f -l", result);
  1655. if(strncmp(result, "Argument", 8) == 0){
  1656. // lkcdutils 4.2
  1657. ret = oChildManager->command("symtab -t -l", result);
  1658. new_symtab=1;
  1659. }
  1660. if (ret) {
  1661. int offset = 0;
  1662. const int len = result.length();
  1663. const char* cptr = result.latin1();
  1664. while (offset < len) {
  1665. CSymtabItem item;
  1666. QString part;
  1667. if(new_symtab){
  1668. // A new line...
  1669. // ignore leading spaces
  1670. offset += strspn(cptr + offset, " \t");
  1671. // Address
  1672. size_t pos = strcspn(cptr + offset, " \t");
  1673. part = result.mid(offset, pos);
  1674. // validate line
  1675. if (part.left(2) != "0x") {
  1676. offset += strcspn(cptr + offset, "\n") + 1;
  1677. continue;
  1678. }
  1679. offset += pos;
  1680. item.setAddress(part);
  1681. offset += strspn(cptr + offset, " \t");
  1682. // Type
  1683. pos = strcspn(cptr + offset, " \n");
  1684. part = result.mid(offset, pos);
  1685. offset += pos;
  1686. item.setType(part);
  1687. offset += strspn(cptr + offset, " \t");
  1688. // Name
  1689. pos = strcspn(cptr + offset, " \t");
  1690. part = result.mid(offset, pos);
  1691. offset += pos;
  1692. item.setName(part);
  1693. list.append(item);
  1694. offset += strcspn(cptr + offset, "\n") + 1;
  1695. } else {
  1696. // A new line...
  1697. // ignore leading spaces
  1698. offset += strspn(cptr + offset, " \t");
  1699. // Address
  1700. size_t pos = strcspn(cptr + offset, " \n");
  1701. part = result.mid(offset, pos);
  1702. // validate line
  1703. if (part.left(2) != "0x") {
  1704. offset += strcspn(cptr + offset, "\n") + 1;
  1705. continue;
  1706. }
  1707. offset += pos;
  1708. item.setAddress(part);
  1709. offset += strspn(cptr + offset, " \t");
  1710. // A digit
  1711. pos = strcspn(cptr + offset, " \n");
  1712. offset += pos;
  1713. offset += strspn(cptr + offset, " \t");
  1714. // Type
  1715. pos = strcspn(cptr + offset, " \n");
  1716. part = result.mid(offset, pos);
  1717. offset += pos;
  1718. item.setType(part);
  1719. offset += strspn(cptr + offset, " \t");
  1720. // Name
  1721. pos = strcspn(cptr + offset, " \n");
  1722. part = result.mid(offset, pos);
  1723. offset += pos;
  1724. item.setName(part);
  1725. list.append(item);
  1726. offset += strspn(cptr + offset, " \t\n");
  1727. }
  1728. }
  1729. }
  1730. return list;
  1731. }
  1732. QString
  1733. QLcrashDoc::getLcrashHelp()
  1734. {
  1735. QString str;
  1736. bool ret = oChildManager->command("help", str);
  1737. return ret ? str : QString::null;
  1738. }