热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何调试一个不太熟悉的代码库?-Howtoapproachdebuggingahugenotsofamiliarcodebase?

Seldomduringworkingonlargescaleprojects,suddenlyyouaremovedontoaprojectwhichisalrea

Seldom during working on large scale projects, suddenly you are moved on to a project which is already in maintainance phase.You end up with having a huge code C/C++ code base on your hands, with not much doccumentation about the design.The last person who could give you some knowledge transfer about the code has left the company already and to add to your horrors there is not enough time to get acquainted with the code and develop an understanding of the overall module/s.In this scenario when you are expected to fix bugs(core dumps,functionality,performance problems etc) on the module/s what is the approach that you will take?

在处理大型项目时,您很少会突然转向已经处于维护阶段的项目。最终,您将拥有一个巨大的代码C/ c++代码库,并没有太多的关于设计的文档。最后一个能够向您提供关于代码的知识转移的人已经离开了公司,为了增加您的恐惧,没有足够的时间来熟悉代码并对整个模块/s进行理解。在这个场景中,当您希望修复模块/s上的bug(核心转储、功能、性能问题等)时,您将采用什么方法?

So the question is: What are your usual steps for debugging a not so familiar C/C++ code base when trying to fix a bug?

所以问题是:当您试图修复一个bug时,调试一个不太熟悉的C/ c++代码库的通常步骤是什么?

EDIT: Enviornment is Linux, but code is ported on Windows too so suggestions for both will be helpful.

编辑:环境是Linux,但是代码也被移植到Windows上,所以对两者的建议都是有用的。

15 个解决方案

#1


20  

If possible, step through it from main() to the problematic area, and follow the execution path. Along the way you'll get a good idea of how the different parts play together.

如果可能的话,从main()逐步到有问题的区域,并遵循执行路径。在这个过程中,你会对不同的部分如何相互作用有一个很好的了解。

It could also be helpful to use a static code analysis tool, like CppDepends or even Doxygen, to figure out the relations between modules and be able to view them graphically.

使用一个静态代码分析工具(比如cppdepend,甚至是Doxygen)来计算模块之间的关系,并能够以图形化的方式查看它们,这也可能是有帮助的。

#2


8  

Use a pen and paper, or images/graphs/charts in general, to figure out which parts belong where and draw some arrows and so on.

使用钢笔和纸,或者图像/图形/图表,来找出哪些部分属于哪里,并画一些箭头等等。

This helps you build and see the image that will then be refined in your mind as you become more comfortable with it.

这将帮助你建立并看到一个形象,当你对它感到更舒适的时候,这个形象将在你的脑海中得到完善。

I used a similar approach attacking a hellish system that had 10 singletons all #including each other. I had to redraw it a few times in order to fit everything, but seeing it in front of you helps.

我使用了一种类似的方法来攻击一个有10个单例的地狱式系统。我不得不重新画了几次,以适应一切,但看到它在你面前是有帮助的。

It might also be useful to use Graphviz when constructing dependency graphs. That way you only have to list everything (in a text file) and then the tool will draw the (often unsightly) picture. (This is what I did for the #include dependencies in above syste,)

在构造依赖图时使用Graphviz可能也很有用。这样,你只需要列出所有的东西(在一个文本文件中),然后工具就会绘制(通常是难看的)图片。(这就是我在上面所做的,包括了上面系的依赖项)

#3


6  

As others have already suggested, writing unit-tests is a great way to get into the codebase. There are a number of advantages to this approach:

正如其他人已经提出的,编写单元测试是进入代码库的一个很好的方法。这种方法有许多优点:

  1. It allows you to test your assumptions about how the code works. Adding a passing test proves that your assumptions about that small piece of code that you are testing are correct. The more passing tests you write, the better you understand the code.

    它允许您测试关于代码如何工作的假设。添加一个通过测试可以证明您对正在测试的那一小段代码的假设是正确的。您编写的通过测试越多,您就越能理解代码。

  2. A failing unit test that reproduces the bug you want to fix will pass when you fix the bug and you know that you have succeeded.

    当您修复了这个错误并且您知道您已经成功时,您想要修复的错误的失败的单元测试将通过。

  3. The unit tests that you write act as documentation for the future.

    您编写的单元测试作为将来的文档。

  4. The unit tests you write act as regression tests as more bugs are fixed.

    您编写的单元测试作为回归测试,因为有更多的bug被修复。

Of course adding unit tests to legacy code is not always an easy task. Happily, a gentleman by the name of Michael Feathers has written an excellent book on the subject, which includes some great 'recipes' on adding tests to code bases without unit tests.

当然,向遗留代码添加单元测试并不总是一件容易的任务。令人高兴的是,一位名叫Michael羽毛的绅士写了一本关于这个主题的优秀著作,其中包括一些伟大的“食谱”,在没有单元测试的情况下,将测试添加到代码库中。

WELC

#4


5  

Some pointers:

一些指针:

  1. Debug from the part which seems more relevant to the workflow.
  2. 从与工作流更相关的部分进行调试。
  3. Use debug strings
  4. 使用调试字符串
  5. Get appropriate .pdb and attach the core dump in debuggers like Windbg or debugdiag to analyze it.
  6. 获取适当的。pdb并在调试器中附加核心转储,如Windbg或debugdiag来分析它。
  7. Get a person's help in your organization who is good at debugging. Even if he is new to your codebase, he could be very helpful. I had prior experience. They would give you valuable pointers.
  8. 在您的组织中得到一个善于调试的人的帮助。即使他是你的代码库新手,他也会很有帮助。我有经验。他们会给你有价值的建议。
  9. Per Assaf Lavie's advice, you could use static code analyzers.
  10. 根据Assaf Lavie的建议,您可以使用静态代码分析器。
  11. The most important thing: as you explore and debug, document everything as you progress. At least the person succeeding you would suffer less.
  12. 最重要的事情:当您探索和调试时,在您进行过程中记录所有内容。至少接替你的人不会那么痛苦。

#5


3  

Three things i don't see yet:

有三件事我还没看到:

  1. write some unit tests which use the libraries/interfaces. demonstrate/verify your understanding of them and promote their maintainability.

    编写一些使用库/接口的单元测试。演示/验证您对它们的理解并提高它们的可维护性。

  2. sometimes it is nice to create an special assertion macro to check that the other engineer's assumptions are in line with yours. you could:

    有时创建一个特殊的断言宏来检查其他工程师的假设是否与您的一致是很好的。你可以:

    1. not commit their uses
    2. 不提交他们的使用
    3. commit their uses, converting them to 'real' assertions after a given period
    4. 提交它们的使用,在给定的时间段后将它们转换为“真正的”断言
    5. commit their uses, allowing another engineer (more familiar with the project) to dispose or promote them to real assertions
    6. 提交它们的使用,允许另一个工程师(更熟悉这个项目)处理或提升它们到真正的断言
  3. refactoring can also help. code that is difficult to read is an indication.

    重构可以帮助。难以阅读的代码是一种指示。

#6


2  

The first step should be try to read the code. Try to see the code where the bug is. Follow the code from main to that point ans try to see what could be wrong. Read the comments from the code(if any). Normally the function names are useful. Understand what each function does.
Once you get some idea of the code then you can start debugging the code. Put breakpoints where you don't understand the code or where you think the error can be. Start following the code line by line. Debugging is like sex. Initially painful, but slowly you start to enjoy it.

第一步应该尝试读取代码。尝试查看错误所在的代码。遵循代码从主到那个点,然后试着看看哪里出了问题。阅读代码中的注释(如果有的话)。通常,函数名是有用的。理解每个函数的作用。一旦您对代码有了一些了解,就可以开始调试代码了。把断点放在你不理解代码的地方或者你认为错误的地方。开始逐行跟踪代码。调试就像性。最初是痛苦的,但慢慢地你开始享受它。

#7


2  

cscope + ctags are available on both Linux and Windows (via Cygwin). If you give them a chance, these tools will become indispensable to you. Although, IDEs like Visual Studio also do an excellent job with code browsing facilities as well.

cscope + ctags可以在Linux和Windows上(通过Cygwin)使用。如果你给他们一个机会,这些工具将成为你不可或缺的。尽管如此,ide如Visual Studio在代码浏览工具方面也做得很好。

In a situation like yours, because of time constraints, you are driven by symptoms. I mean that you don't have time to reconstruct the big picture / design / architecture. So you focus on the symptoms and work outwards, and each time reconstruct as much of the big picture as you need for that particular problem. But do not make "local" decisions in a hurry. Have the patience to see as much of the big picture as needed to make a good quality decision. And don't get caught in the band-aid syndrome i.e. put any old fix in that will work. It is your job to preserve the underlying architecture / design (if there is one, and to whatever extent that you can discover it).

在你这样的情况下,由于时间的限制,你会被症状所驱动。我的意思是你没有时间去重建大的图景/设计/架构。所以你关注症状并向外努力,每次重建你所需要的那个特定问题的大图景。但不要匆忙地做出“本地”决定。要有耐心,尽可能多地看到大局,以便做出高质量的决定。不要陷入创可贴综合症,也就是说,用旧的疗法治疗就可以了。您的工作是维护底层架构/设计(如果有的话,并且您可以在任何程度上发现它)。

It will be a struggle at first, as your mind "hunts" excessively. But soon the main themes in the design / architecture will emerge, and all of it will start to make sense. Think, by not thinking, grasshoppa :)

当你的大脑过度“狩猎”时,一开始会是一场斗争。但不久,设计/架构中的主要主题将出现,所有这些都将开始变得有意义。想想,不要去想,蚱蜢:

#8


1  

You have to have a fully reliable IDE which has a lot of debbugging tools (breakpoints, watches, and the like). The best way to familiarize yourself with a huge code is to play around with it and see how data is passed from one method to another. Also, you can reverse engineer the code so could see the relationship of the classes. :D Good Luck!

您必须有一个完全可靠的IDE,其中包含大量的漏洞工具(断点、手表等)。熟悉大型代码的最好方法是使用它,查看数据如何从一个方法传递到另一个方法。此外,您还可以反向设计代码,以便查看类的关系。D:祝你好运!

#9


1  

For me, there is only one way to get to know a process - Interaction. Identify the interfaces of the process/system. Then identify the input/output relationship (these steps maybe not linear). Once you do that, you can start tinkering at the code with a fair amount of confidence because you know what it is "supposed to do" then it's just a matter of finding out "how it is actually being done". For me though, getting to know the interface (Not necessarily the user interface) of the system is the key. To put it bluntly - Never touch the code first!!!

对我来说,了解过程只有一种方法——交互。确定流程/系统的接口。然后确定输入/输出关系(这些步骤可能不是线性的)。一旦您这样做了,您就可以开始对代码进行大量的修改了,因为您知道它“应该做什么”,那么问题就在于找到“它实际上是如何做的”。对我来说,了解系统的界面(不一定是用户界面)是关键。坦率地说——永远不要接触代码!!!

#10


1  

Not sure about C/C++, but coming from Java and C#, unit testing will help. In Java there's JUnit and TestNG libraries for unit testing, in C# there's NUnit and mstest. Not sure about C/C++.

不确定C/ c++,但是来自Java和c#,单元测试将会有所帮助。在Java中有用于单元测试的JUnit和TestNG库,在c#中有NUnit和mstest。对C / c++不确定。

Read the book 'Refactoring: Improving the Design of Existing Code' by Martin Fowler, Kent Beck, et al. Will be quite a few tips in there I'm sure that will help, and give you some guidance to improving the code.

阅读Martin Fowler、Kent Beck等人的《重构:改进现有代码的设计》一书,我相信这将会对您有所帮助,并为您提供一些改进代码的指导。

One tip: if it aint broke, don't fix it. Don't bother trying to fix some library or really complicated function if it works. Focus on parts where there's bugs.

一个提示:如果没有坏,不要去修理。不要费事去修复某个库,如果它可以工作的话,也不要去修复那些非常复杂的函数。关注有缺陷的部分。

Write a unit test to reproduce the scenario where the code should work. The test will fail at first. Fix the code until the unit test passes successfully. Repeat :)

编写一个单元测试来重现代码应该工作的场景。考试一开始就会不及格。修改代码直到单元测试成功通过。重复一遍:)

Once a majority of your code, the important bits that are too complex to manually debug and fix, is under automated unit tests, you'll have a safety harness of regression tests that'll make you feel more confident at changing the existing code base.

一旦您的大部分代码(手工调试和修复太复杂的重要部分)都在自动的单元测试之下,您将获得回归测试的安全控制,这将使您在更改现有代码库时更加自信。

#11


1  

while (!codeUnderstood)
{
  Breakpoints();
  Run();
  StepInto();
  if(needed)
  { 
   StepOver();
  }
}

#12


1  

I don't try to get an overview of the whole system as suggested by many here. If there is something which needs fixing I learn the smallest part of the code I can to fix the bug. The next time there is an issue I'm a little more familiar and a little less daunted and I learn a little more. Eventually I'm able to support the whole shebang.

我不像这里的许多人所建议的那样试图获得整个系统的概述。如果有什么需要修改的地方,我可以学习代码中最小的部分来修复bug。下次有问题的时候,我会更熟悉一些,也不会那么害怕,我也会学到更多。最终我能支撑起整个过程。

If management suggests I do a major change to something I'm not familiar with I make sure they understand the time scales and if things a really messy suggest a rewrite.

如果管理层建议我对一些我不熟悉的东西做一个大的改变,我要确保他们理解时间尺度,如果事情真的很混乱,就建议重写。

#13


1  

Usually the program in question will produce some kind of output ( log, console printout, dialog box ).

通常问题中的程序会产生某种输出(日志、控制台打印输出、对话框)。

  1. Find the closest place to your problem in the program output
  2. 在程序输出中找到与您的问题最近的位置
  3. Search through the code base and look for the text in that output
  4. 搜索代码库并在输出中查找文本
  5. Start putting your own printouts, nothing fancy, just printf( "Calling xxx\n" );, so you can pinpoint exactly to the point where the problem starts.
  6. 开始放置您自己的打印输出,没有什么特别的,只是printf(“调用xxx\n”);这样您就可以精确地找到问题开始的地方。
  7. Once you pinpointed the problem spot, put a breakpoint
  8. 一旦确定了问题点,就设置一个断点
  9. When you hit the breakpoint, print a stacktrace
  10. 当您到达断点时,打印一个堆栈跟踪。

Now you can see what players you have and start the analysis of how you've got to the wrong place.

现在你可以看到你有哪些球员,并开始分析你是如何走错地方的。

Hopefully the names of the methods on the call stack are more meaningful than a, b and c ( seen this ), and there is some sort of comments, method documentation more meaningful than calling a ( seen this many times ).

希望调用堆栈上方法的名称比a、b和c更有意义(见过这个),并且有一些注释,方法文档比调用a更有意义(见过很多次)。

If the source is poorly documented, don't be afraid to leave your comments once you have figured out what's going on. If program design permits it create a unit test for the problem you've fixed.

如果消息来源的文档记录很糟糕,一旦你弄明白是怎么回事,不要害怕留下你的评论。如果程序设计允许它为您已经修复的问题创建一个单元测试。

#14


1  

Thanks for the nice answers, quite a number of points to take up. I have worked on such situation a number of times and here is the usual procedure i follow:

谢谢你这么漂亮的回答,有很多问题需要考虑。我曾多次处理过这种情况,以下是我通常遵循的程序:

  1. Check the crash log or trace log. Check relevant trace if just a simple developer mistake if cannot evaluate in one go, then move on to 2.
  2. 检查崩溃日志或跟踪日志。检查相关跟踪如果只是一个简单的开发人员错误,如果不能一次性评估,那么继续到2。
  3. Reproduce the bug! This is the most important thing to do. Some bugs are rare to occur and if you get to reproduce the bug nothing like it. It means you have a better % of cracking it.
  4. 复制错误!这是最重要的事情。有些错误很少发生,如果你复制这个错误就不会发生。这意味着你有更好的百分比来破解它。
  5. If you cant reproduce a bug, find a alternative use case, situation where in you can actually reproduce the bug. Being able to actually debug a scenario is much more useful than just the crash log.
  6. 如果您不能复制错误,请找到一个替代的用例,在这种情况下,您实际上可以复制错误。能够实际调试场景要比只调试崩溃日志有用得多。
  7. Head to version control! Check if the same buggy behavior exists on previous few SW versions. If NOT..Voila! You can find between what two versions the bug got introduced and You can easily get the code difference of the two versions and target the relevant area.(Sometimes it is not the newly added code which has the bug but it exposes some old leftovers.Well, We atleast have a start I would say!)
  8. 头版本控制!检查在以前的几个版本中是否存在相同的错误行为。如果不是,瞧!您可以在两个版本之间找到bug,您可以轻松获得两个版本的代码差异,并针对相关区域。(有时并不是新添加的代码有bug,而是暴露了一些旧的遗留问题。好吧,我想我们至少有一个开始!
  9. Enable the debug traces. Run the use case of the bug, check if you can find some additional information useful for investigation.
  10. 启用调试痕迹。运行这个bug的用例,检查是否可以找到一些对调查有用的附加信息。
  11. Get hold of the relevant code area through the trace log. Check out there for some code introducing the bug.
  12. 通过跟踪日志获取相关代码区域。查看一些引入bug的代码。
  13. Put some breakpoints in the relevant code. Study the flow. Check the data flows.Lookout for pointers(usual culprits). Repeat till you get a hold of the flow.
  14. 在相关代码中添加一些断点。研究流。检查数据流。寻找指针(罪犯)。重复,直到你掌握了气流。
  15. If you have a SW version which does not reproduce the bug, compare what is different in the flows. Ask yourself, Whats the difference?
  16. 如果您有一个不再现错误的SW版本,请比较流中的不同之处。问问你自己,有什么不同?
  17. Still no Luck!- Arghh...My tricks have exhausted..Need to head the old way. Understand the code..and understand the code and understand it till you know what is happening in the code when that particular use case is being executed.
  18. 仍然没有运气!-是的…我的技巧已经用尽了. .需要走老路。理解代码. .理解代码并理解它,直到您知道在执行特定用例时代码中发生了什么。
  19. With newly developed understanding try debugging the code and sure the solution is around the corner.
  20. 有了新开发的理解,试着调试代码,确保解决方案就在眼前。
  21. Most important - Document the understanding you have developed about the module/s. Even small knitty gritty things. It is sure going to help you or someone just like you, someday..sometime!
  22. 最重要的是——记录你对模块/s的理解。甚至是小的针织品。总有一天,它一定会帮助你或像你一样的人。

#15


0  

You can try GNU cFlow tool (http://www.gnu.org/software/cflow/). It will give you graph, charting control flow within program.

您可以尝试GNU cFlow工具(http://www.gnu.org/software/cflow/)。它会给你图形,在程序中绘制控制流。


推荐阅读
  • 如何高效启动大数据应用之旅?
    在前一篇文章中,我探讨了大数据的定义及其与数据挖掘的区别。本文将重点介绍如何高效启动大数据应用项目,涵盖关键步骤和最佳实践,帮助读者快速踏上大数据之旅。 ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • POJ 2482 星空中的星星:利用线段树与扫描线算法解决
    在《POJ 2482 星空中的星星》问题中,通过运用线段树和扫描线算法,可以高效地解决星星在窗口内的计数问题。该方法不仅能够快速处理大规模数据,还能确保时间复杂度的最优性,适用于各种复杂的星空模拟场景。 ... [详细]
  • SQLite数据库CRUD操作实例分析与应用
    本文通过分析和实例演示了SQLite数据库中的CRUD(创建、读取、更新和删除)操作,详细介绍了如何在Java环境中使用Person实体类进行数据库操作。文章首先阐述了SQLite数据库的基本概念及其在移动应用开发中的重要性,然后通过具体的代码示例,逐步展示了如何实现对Person实体类的增删改查功能。此外,还讨论了常见错误及其解决方法,为开发者提供了实用的参考和指导。 ... [详细]
  • 本文深入探讨了CGLIB BeanCopier在Bean对象复制中的应用及其优化技巧。相较于Spring的BeanUtils和Apache的BeanUtils,CGLIB BeanCopier在性能上具有显著优势。通过详细分析其内部机制和使用场景,本文提供了多种优化方法,帮助开发者在实际项目中更高效地利用这一工具。此外,文章还讨论了CGLIB BeanCopier在复杂对象结构和大规模数据处理中的表现,为读者提供了实用的参考和建议。 ... [详细]
  • 本文详细介绍了 jQuery 的入门知识与实战应用,首先讲解了如何引入 jQuery 库及入口函数的使用方法,为初学者提供了清晰的操作指南。此外,还深入探讨了 jQuery 在实际项目中的多种应用场景,包括 DOM 操作、事件处理和 AJAX 请求等,帮助读者全面掌握 jQuery 的核心功能与技巧。 ... [详细]
  • 在使用 Qt 进行 YUV420 图像渲染时,由于 Qt 本身不支持直接绘制 YUV 数据,因此需要借助 QOpenGLWidget 和 OpenGL 技术来实现。通过继承 QOpenGLWidget 类并重写其绘图方法,可以利用 GPU 的高效渲染能力,实现高质量的 YUV420 图像显示。此外,这种方法还能显著提高图像处理的性能和流畅性。 ... [详细]
  • 在Android平台中,播放音频的采样率通常固定为44.1kHz,而录音的采样率则固定为8kHz。为了确保音频设备的正常工作,底层驱动必须预先设定这些固定的采样率。当上层应用提供的采样率与这些预设值不匹配时,需要通过重采样(resample)技术来调整采样率,以保证音频数据的正确处理和传输。本文将详细探讨FFMpeg在音频处理中的基础理论及重采样技术的应用。 ... [详细]
  • MyISAM和InnoDB是MySQL中最为广泛使用的两种存储引擎,每种引擎都有其独特的优势和适用场景。MyISAM引擎以其简单的结构和高效的读取速度著称,适用于以读操作为主、对事务支持要求不高的应用。而InnoDB引擎则以其强大的事务处理能力和行级锁定机制,在需要高并发写操作和数据完整性的场景下表现出色。选择合适的存储引擎应综合考虑业务需求、性能要求和数据一致性等因素。 ... [详细]
  • 尽管我们尽最大努力,任何软件开发过程中都难免会出现缺陷。为了更有效地提升对支持部门的协助与支撑,本文探讨了多种策略和最佳实践,旨在通过改进沟通、增强培训和支持流程来减少这些缺陷的影响,并提高整体服务质量和客户满意度。 ... [详细]
  • 汽车电子架构与CAN网络基础解析——鉴源实验室专业解读 ... [详细]
  • 在TypeScript中,我定义了一个名为 `Employee` 的接口,其中包含 `id` 和 `name` 属性。为了使这些属性可选为空,可以通过使用 `| null` 或 `| undefined` 来扩展其类型定义。例如,`id: number | null` 表示 `id` 可以是数字或空值。这种类型的灵活性在处理不确定的数据时非常有用,可以提高代码的健壮性和可维护性。 ... [详细]
  • 《Intel IA-32 架构软件开发人员手册详尽指南》提供了详尽的 IA-32 架构技术文档,涵盖指令集、系统编程和硬件接口等内容,为软件开发人员提供全面的技术支持和参考。该手册不仅包括详细的架构说明,还提供了丰富的编程示例和最佳实践,帮助开发人员更好地理解和应用 IA-32 架构。 ... [详细]
  • 投融资周报 | Circle 达成 4 亿美元融资协议,唯一艺术平台 A 轮融资超千万美元 ... [详细]
  • 在托管C++中开发应用程序时,遇到了如何声明和操作字符串数组的问题。本文详细探讨了字符串数组在托管C++中的应用与实现方法,包括声明、初始化、遍历和常见操作技巧,为开发者提供了实用的参考和指导。 ... [详细]
author-avatar
mobiledu2502855913
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有