【问题标题】:programmatically mocking a function以编程方式模拟函数
【发布时间】:2011-12-09 13:18:27
【问题描述】:

有没有办法以编程方式模拟在 linux 上运行的嵌入式 c 应用程序的函数。在下面的示例中,我想模拟 main 在运行时调用 someBlah 而不是 someFunc。

#include <stdio.h>

void someFunc( void )
{
    printf("%s():%d\n",__func__,__LINE__);
}

void someBlah( void )
{
    printf("%s():%d\n",__func__,__LINE__);
}

int main(void)
{
    someFunc();
}

该程序将在 Linux 中从 ram 执行,因此文本段应该是可修改的。我知道 GDB 在一些类似的概念上工作,其中断点代码位置被陷阱指令替换。

【问题讨论】:

    标签: c linux embedded linux-kernel


    【解决方案1】:

    当然,只需制作一个函数指针表。

    #define BLAH 0
    #define FOO 1
    void (*table_function[])(void) = {someBlah, someFoo};
    

    如果它们都有相同的接口和返回类型,你可以通过切换表项来切换它们。

    然后你通过执行调用一个函数

    table_function[BLAH]();
    

    如果你想交换一个函数,直接说

    table_function[BLAH] = otherBlah;
    

    另外:除非您正在编写某种 JIT 编译环境或虚拟机,否则不要这样做,通常您不需要此类结构,如果您需要它们,您可能会遇到糟糕的架构日。

    尽管如果您在 OO 设计方面有经验,您可以用这种方式在 C 中设计多态结构(如果没有意义,请忽略这一点)。

    【讨论】:

    • 或者实现虚拟表:)
    • 在我们的例子中,我无法更改父函数中的实现它的“main()”
    • 不,我的问题与VM / OO设计无关,我们正在尝试提出平台单元测试,因此要求是模拟但在运行时。
    【解决方案2】:

    您始终可以通过适当调用 mprotect 来修改文本段的某些部分,并用您自己的代码覆盖一些代码(例如,通过使用 libjit、GNU 闪电生成机器代码...或手动)。

    但是使用函数指针是一种更简洁的方法。

    如果函数位于共享库中,您甚至可以覆盖其 Procedure Linkage Table(另请参阅 ABI spec,这取决于架构 - 这里是 ARM 的一个)

    【讨论】:

    • 我还没有尝试你的方法,但它看起来很合适。所以接受你的回答。
    【解决方案3】:

    有一些 C 的模拟框架。

    在工作中,cgreen 取得了一些成功,但我们确实必须对其内部进行更改。幸运的是,它非常小,因此相对容易扩展。一个看起来不错但我没有使用过的替代方法是 Unity 和 CMock 的组合。

    关于单元测试嵌入式 C 代码的一般主题,我强烈推荐Test Driven Development for Embedded C。

    【讨论】:

      【解决方案4】:

      我这样做的另一种方法是:

      #include <stdio.h>
      #define DEBUG
      
      void someFunc( void )
      {
      #ifndef DEBUG
          printf("%s():%d\n",__func__,__LINE__);
      #else
          printf("%s():%d\n",__func__,__LINE__);
      #endif
      }
      
      int main(void) 
      {
          someFunc();
      }
      

      【讨论】:

        【解决方案5】:

        看看CMocka,有一篇关于LWN上mock的文章:Unit testing with mock objects in C

        【讨论】:

          猜你喜欢
          • 2015-02-25
          • 1970-01-01
          • 1970-01-01
          • 2012-10-25
          • 2016-12-21
          • 1970-01-01
          • 1970-01-01
          • 2013-02-17
          • 1970-01-01
          相关资源
          最近更新 更多