Browsed by
分类:wine

[wine] 将WindowsPath转为UnixPath的解决方案

[wine] 将WindowsPath转为UnixPath的解决方案

参考这个代码

wine-devel maling list

要在wine下实现对wpcap的兼容, 使用了wrapper的手段来进行, 即不自己实现wpcap的相应函数, 通过调用Linux下的pcap相应的函数, 达到同样的效果. 这个函数的作用是将监听到的数据dump到fname指定的文件里, 因Linux下的文件路径和Windows的不同, 想要调用LInux原生的pcap_dump_open之前需要进行路径的转换,因此尝试进行修改, 变成这个样子:

然后很干脆的跪了

Convert to Widechar 就出问题了 , 经过查看MSDN 的MultiByteToWideChar得到了相应的信息:

https://msdn.microsoft.com/en-us/library/windows/desktop/dd319072(v=vs.85).aspx 参考MSDN

cchWideChar [in]

Size, in characters, of the buffer indicated by lpWideCharStr. If this value is 0, the function returns the required buffer size, in characters, including any terminating null character, and makes no use of the lpWideCharStr buffer.

因为我的cchWideChar = 0 所以转换后的结果没有存到fname_W里, 因而转换失败

 

在IRC上请教了wine开发者之后, 选用了RtlInitAnsiString + RtlAnsiStringToUnicodeString + RtlDosPathNameToNtPathName_U + wine_nt_to_unix_file_name 的方法, 注意 一定要有 RtlDosPathNameToNtPathName_U 这个函数, 将 由前两个函数转换得到的DosPath转换为NtPath, 不然在wine_nt_to_unix_file_name的时候会出错(STATUS_OBJECT_NAME_INVALID) 不合法的NtPath, 然后经过修改的代码如下:

这个代码还有内存泄露和没有错误检查的问题, 需要继续修改,不过已经可以将winpath转换为unixpath了

setcap wine 遇到的问题解决

setcap wine 遇到的问题解决

之后为了让普通用户也能通过wine访问到网络接口,需要给wine的相关程序(wine-preloader 和 wineserver wine) 一些特权

 

参考  man capabilities 和 setcap

  •  首先需要给CAP_NET_RAW 权限 这个要给到 wine-preloader 上,不过在设置完这个权限之后,执行 wine XXX.exe 会报错

wine: error while loading shared libraries: libwine.so.1: cannot open shared object file: No such file or directory

这是因为特权模式的程序运行的时候是不会检测到相对路径的lib库的, 具体参考文章如下:http://stackoverflow.com/q/6493846/296473  解决方法在文中已有了 就不赘述了

  •  上述问题解决后,运行wine 会提示  Internal errors- Invalid parameters  , 而且winedbg不可以attach到进程, 这个问题的解决方法是给wineserver(不是wine-preloader)CAP_SYS_PTRACE权限

 

 

__attribute__ in C

__attribute__ in C

__atrribute__ in C

Take a look at this code for example (in Cygwin master branch /winsup/cygwin/winsup.h)

Then gcc xxx.c and then run the code it will print out “Hello World” ~

So why it works?

The code with constructor attribute run before main function and code with destructor attr run after main function

The __attribute__ can do more than above

Another usage of __attribute__ is to customize the section of a certain code , take a look at this example:

Then compile the code and run readelf tool to check the section in the code:
$ readelf -S a.out

You can see a section called my_custom_section and with AX acess(alloc + executable)

This proves that we can use __attribute__ to customize the section

Windows 下同步(多线程协调)的实现 的简单解释

Windows 下同步(多线程协调)的实现 的简单解释

Windows下的多个线程之间的通信,是通过各种Object进行的, 目前我只了解到EventObject, 下面简单介绍一下什么是EventObject .

我们可以把各个线程想象成一些不同的流水线,比如制作面包的流水线, 一个线程(流水线)负责制作面包,另一个流水线负责将面包包装好,那么这两个流水线就存在逻辑上的顺序, 即使他们同时工作,包装的如果不等制作面包的制作好,是无法进行的. 在系统里也是这样 两个(或者多个)线程之间有依赖关系, 比如B要在A完成后才可以处理,C要等D E完成之后才能处理. 那么,多个线程之间如何协调好这个关系呢. 这时候Windows就使用EventObject来给各个线程发送信号,EventObject可以有名字也可以没有名字, 带名字的在多线程同步时很常用(这里说明一下 ,多个线程之间协调工作就叫同步), 在多线程同步处理事件的时候 , 首先建立好一系列的EventObject(和其他Object) ,然后 线程A执行开始的时候 将EventObjectA设置为FALSE(没被触发状态) 这时 线程B在等待EventObjectA的信号(就是保持挂起状态,一旦有信号激活就会开始执行) , 然后线程A执行完毕之后 , 就会将EventObjectA设置为TRUE (触发状态) 这时, 由于EventObjectA被触发, 线程B也就同时启动了,然后开始执行线程B,这样就实现了线程之间的同步

有关NtCreateEvent和 EventObject的说明 参见msdn文档

https://msdn.microsoft.com/en-us/library/windows/hardware/ff566423(v=vs.85).aspx NtCreateEvent 的介绍

https://msdn.microsoft.com/en-us/library/windows/desktop/ms682655(v=vs.85).aspx EventObject的介绍

mingw 和 MSYS 的区别

mingw 和 MSYS 的区别

最近在wine下使用msys和mingw进行一些交叉编译和测试0.0 对于什么时候用msys的shell 什么时候用mingw 有些困惑 ,现在大致明白了二者的区别 ,在此总结一下.

mingw实际上是minimalist GNU for windows的缩写 ,也就是mingw提供了一个简化的GNU开发组件(如automake gcc 等) 是gcc 和 gnu binutils 在Windows上的移植,这些程序可以直接在Windows的环境下运行 他们依赖的是msvcrt.dll这些Windows下系统自带的库,不借助外部库就可以使用 .

msys是Minimal SYStem 的缩写 ,他提供了调用Linux下的系统函数 (如 open flock等)的一个集合 , 因此msys可以用来编译原生的Linux上的代码 , 但是mingw不可以,因为mingw内没有提供调用Linux系统函数的功能,不过相应的,运行在msys下编译好的具有POSIX C代码的可执行程序的时候 ,需要加载msys自己的dll , 因此这个程序不能独立的在windows系统下运行 而需要依赖msys的dll

如果想要验证我的说法的话 , 可以在自己机器上先配置好msys32 安装好 ,然后 首先在MSYS下编译一个有POSIX C代码的程序 编译为 exe格式 ,然后 在Windows的资源管理器中找到这个程序直接执行,  你会发现这个程序执行不了 错误是需要MSYS的dll  , 这样就验证了我的第二条总结 . 同样的,将这段代码带到mingw下命令行下, 然后用mingw的编译器进行编译 , 你会发现编译出问题 编译器找不到POSIX C的函数的头 ,如果你将header文件人为安装好,那么链接器会出错 , 找不到对POSIX C函数的定义 . 因此验证了我总结的第一条

 

关于如何安装mingw msys 在Windows上 ,很多blog都已经说明了这里不再赘述,查看官方文档或者查看blog都可以解决这个问题

gdb 下调试多线程

gdb 下调试多线程

最近接触的工作需要多线程的一些知识才能完成,而以前没有多线程相关知识,现在进行一些简单的学习和研究.本文内容偏向实践,对于想要了解原理的请去看计算机线程方面的资料和书籍.

1.gdb下调试多进程代码的注意事项

最近在调试这样一段代码的时候, 由于我不具备任何多线程的知识,导致我在找错误的时候出现了严重的问题,代码如下:

调试环境为在Linux下的Wine下运行的MSYS2(32bit) 在MSYS2内运行的gdb, 这段代码在运行到

这一行的时候 就出现了错误,导致我认为是fork出了问题,不过实际上不是这样的, 在我了解fork的具体操作后,才明白了为什么错误不发生在fork这一行但是却在fork上报错. 下面将会解释上面这个问题  首先要从fork的应用来说.

通过查看 man 2 fork我们可以了解到fork的使用方法和返回值的含义,  fork的作用是在某一个程序运行到fork()这里的时候 ,新开一个线程,这个线程与原来的线程独立,不过线程内的变量值等信息都与原来的线程一致, (他们不共用内存地址) , 这个线程就称为子进程, 原来的进程就叫做父进程. fork()的返回值为一个进程号, 返回的进程号为当前父进程的子进程的进程号,子进程的这个返回值为0(注意子进程是相对父进程而言) .

另外 在使用gdb调试的时候 ,如果出现了多线程的代码 ,那么不进行任何设置的情况下,gdb不会阻止(控制)子进程的执行,也就是说,就算你在用step in 或者next 对代码进行调试 ,但是遇到了 fork()之后 ,子进程会自动执行从 fork开始到代码末尾的所有语句,不会受gdb控制, 因而 ,如果是在fork之后的代码出了问题, 那么在用没有配置的gdb进行单步调试的时候,代码会在父进程fork之后报错,这样就不便于定位错误的位置. 下面用一段代码来验证一下我的这个说法:

上面这段代码做的事情很简单 ,我就不再多解释 ,将这段代码用 gdb -g -O0 编译之后  在gdb下调试

首先使用 start > tmpfile来启动调试进程, 这样所有的输出都会被重定向到一个文件 ,不会因为gdb的原因导致输出延迟, 然后 使用 next指令 执行完 fork这一行, 然后立即查看tmpfile的内容 你会发现 tmpfile的内容为:

我们明明还没有执行到下一个printf,但是却输出了forked PID is 0 , 通过上文我们知道了 PID为0 意味着打印这个信息的进程为子进程 这也就说明了 gdb没有阻拦子进程的执行 ,让子进程执行完毕了,但是父进程依旧在被gdb控制,因此,如果是fork之后的代码出现了问题,由于未经配置的gdb不能监视子进程,子进程自动执行到出错的地方然后扔出错误信息,但是我们在gdb上看到的现象却是执行fork的时候报错了,这样就导致了判断不出来错误的所在.

2.用gdb调试多线程

那么遇到多线程的代码的时候应该如何调试呢, 官方文档给出了三种方法 https://sourceware.org/gdb/onlinedocs/gdb/Forks.html

相关信息已经有很好的列出,在这里就不多解释了. 不过需要注意一点 ,就是在无法使用 follow-fork-mode 和 follow-exec-mode的时候 (比如kernel版本不对,平台不对之类的问题) 那么就要在代码里插入sleep来进行调试, 这个方法是通用的一个方法

 

3.依旧存在疑惑的地方

上面那段代码 ,如果直接执行(将信息输出到stdout上) 那么结果为:

 

这样三行内容    而如果重定向到文件或者管道的话 ,内容则变为:

四行, 具体一为什么会出现这一现象的原因有待深入学习fork和重定向的相关知识

Wine 调试bug总结(MSYS2篇)

Wine 调试bug总结(MSYS2篇)

我将如何调试MSYS2中的某个开源程序的bug的过程总结下来,提供给需要的人
1.配置好环境
– 获得wine-staging的源码
* clone最新的wine代码
* clone wine-staging的代码
* 在wine-staging下使用 patchinstall.sh脚本 将wine-staging的改动应用到wine的代码树上
– 编译并安装wine
* 安装编译wine需要的库文件(参见Winehq的官方资料)
* configure并且编译安装代码
2.利用自己配置好的环境重现bug 注意一定要下载正确版本的代码进行编译3.下载要debug的软件安装的源码并且编译成有符号表的程序 在 gdb下调试 利用step in 和 next 等命令 ,找出bug发生的地方(就是出现fault 的那个点)
-在MSYS2下git clone不可以用 因此需在Linux下进行某些代码的clone 然后再makepkg的时候i记得加上 –noextract 参数
– 学习PKGBUILD的语法和写法
– 学习makepkg 等指令 ( 如果不能通过checksum checkpgp 就用 –skippgpcheck 和 –skipchecksums 跳过)
4.阅读该程序的源代码 , 从bug发生的点向上找, 找出问题所在 , 定位到函数内, ( 如果bug是因为SIGSEGV , 那么找出哪个变量的访问发生了SIGSEGV, 并且确定出何时这个变量不能被access了)
5.通过搜集到的信息写出POSIX C 的测试样例 重现此bug (此时应该结合Google man page 以及各种资料 找出你要使用的函数的用法,以及作用)
7.进一步研究自己写好的测试样例, 用 RELAY日志把程序运行时的系统日志收集到
–  根据要记录的日志的模块的不同 WINEDEBUG后加不同的参数 , 不过所有的都要 WINEDEBUG=+relay,+tid,+server , 而且要注意 server加上后 ,先执行
wineserver -k 然后再启动你要调试的程序 ,server的日志只有在第一个wine的进程启动时,启动server才会记录 , 关于这些参数的意义 +relay表示输出relay日志 , +tid表示打印日志的时候带有线程号 , +server表示i记录下server的详细日志
– 得到日志之后 需要对日志进行处理,才能获得有用的信息 ,处理方法如下
* 先grep “Starting process” (大小写自己确认一下) 然后找到你运行的程序的名字 ,然后找到进程号
* grep那个进程号,将结果存下来
*  根据你修复的bug不同 ,可能有不同的特点 ,比如特殊的参数 或者特殊的字符串(如打开的文件的名字) 找到与这个bug关系密切的系统函数 , 大致理解这个bug是由什么样的系统调用产生的.
* 关于如何读relay的日志 , 参考Wine -Developer manual
* 将关键的行提取出来,形成一个新的日志 ,并且整理出调用关系 .
6.进一步将调用的细节确定下来
– 编译安装MSYS2-runtime的代码,要有 -g 参数 (如果编译完成不了的话,甚至源码无法get到的话 ,请看第三步)
* 编译安装的几个细节 ,首先PKGBUILD里的options一定要有debug, runtime的代码库要自己先clone好 同时要注意使用noextract , 编译好pkg文件之后 将两个.pkg.tar.xz文件一起安装 用 pacman -U .pkg.tar.xz 即可,也可以到PKG文件(名称记不清楚)里修改,把git的地址修改成自己本地的源码

  • 安装好之后需要重启一下 MSYS2 ,然后 对程序进行单步调试, step in 到MSYS2-runtime的代码 , 找出和这个bug有关的系统调用,然后 整理出来整个系统调用的详细脉络,包括每次调用的参数
    (这里要注意一点: 如果某个参数是一个指针 ,要记录下来这个指针指向的内容的各个参数 , 而不是仅仅记录这个地址)
    7.写出WinAPI版本的测试用例
  • 根据6收集到的足够的信息 , 然后可以开始写样例了~
  • 根据收集到的信息写好样例( 最好将所有16进制的数都写成英文宏定义的形式)
  • 在Windows上和Linux上进行样例的测试 . 检测一致性