Who's Online |
49 user(s) are online ( 45 user(s) are browsing Forums)
Members: 0
Guests: 49
more...
|
|
|
|
Re: Snork: New Tracing Tool for AmigaOS 4
|
Posted on: 6/29 10:07
#21
|
Home away from home 
|
@msteed Quote: Typically, your current approach -- doing as little as possible in the patch, and postponing the formatting and output to Snork itself -- is the recommended way to handle such things. But I wonder if in this case your original approach -- doing everything, including the DebugPrintF(), in the patch -- isn't a better idea.
I switched to IPC only because I started losing strings (some had garbage when they shouldn't). Maybe it was a side effect of a bug or something else, but once I began copying strings and tags in the patch and sending them via messages, the bug disappeared. But of course, this means I now have more code to handle, like first copying, then parsing, and overall it’s starting to be a bit too much, but still probably safer... Quote: One drawback to the current approach is that logging the function call is asynchronous to the function call itself- by the time Snork gets the message and outputs the log, the call has already occurred. So if the call crashes due to a bad argument, the crash occurs before the call can be logged (and if the crash takes down the system, the log will never be written).
A bigger problem comes up when you start logging exec.library calls. I presume you allocate memory in the patch to hold all the copies of arguments, and memory allocation can break a Forbid() that might be in effect when Exec is called. It looks like that can be prevented by using the AVT_Wait, FALSE tag with AllocVecTags().
Yes, for copying strings and tags, I use AllocVecTags, and currently my GenericPatch function and SendIPCMessage function look like this: Patching function:
void GenericPatch(struct Interface *Self, int watchIndex, uint32 args[MAX_PARAMS]) {
if (watchIndex < 0 || watchIndex >= watchCount || !watches[watchIndex].origFunc ||
!watches[watchIndex].iface || Self != watches[watchIndex].iface) {
IExec->DebugPrintF("Invalid watchIndex or interface mismatch: watchIndex=%d\n", watchIndex);
return;
}
struct Watch *watch = &watches[watchIndex];
// Prepare parameter types for IPC message
char paramTypes[MAX_PARAMS] = {0};
for (int i = 0; i < watch->paramCount && i < MAX_PARAMS; i++) {
paramTypes[i] = watch->params[i].type;
}
// Handle process filter and task info
if (showProcessName || showTaskInfo) {
char taskName[256];
struct Process *proc = (struct Process *)IExec->FindTask(NULL);
Get_Name(taskName, sizeof(taskName), proc);
if (!showProcessName || strcmp(taskName, showProcessName) == 0)
SendIPCMessage(watchIndex, args, watch->libName, watch->funcName, paramTypes,
showTaskInfo ? taskName : NULL, showTaskInfo ? (uint32)proc : 0);
} else {
SendIPCMessage(watchIndex, args, watch->libName, watch->funcName, paramTypes, NULL, 0);
}
// Call the original function with the appropriate number of parameters
typedef void (*FuncPtr)(struct Interface *, ...);
FuncPtr origFunc = (FuncPtr)watch->origFunc;
switch (watch->paramCount) {
case 0: origFunc(Self); break;
case 1: origFunc(Self, args[0]); break;
case 2: origFunc(Self, args[0], args[1]); break;
case 3: origFunc(Self, args[0], args[1], args[2]); break;
case 4: origFunc(Self, args[0], args[1], args[2], args[3]); break;
case 5: origFunc(Self, args[0], args[1], args[2], args[3], args[4]); break;
case 6: origFunc(Self, args[0], args[1], args[2], args[3], args[4], args[5]); break;
case 7: origFunc(Self, args[0], args[1], args[2], args[3], args[4], args[5], args[6]); break;
case 8: origFunc(Self, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); break;
case 9: origFunc(Self, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); break;
case 10: origFunc(Self, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); break;
case 11: origFunc(Self, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]); break;
default:
IExec->DebugPrintF("Debug: Unsupported parameter count %ld\n", watch->paramCount);
break;
}
}
SendIPCMessage():
void SendIPCMessage(int watchIndex, uint32 args[MAX_PARAMS], const char *libName, const char *funcName, const char paramTypes[MAX_PARAMS], const char *taskName, uint32 taskAddr) {
if (!ipcPort) {
IExec->DebugPrintF("IPC port not initialized!\n");
return;
}
struct IPCMessage *ipcMsg = IExec->AllocVecTags(sizeof(struct IPCMessage),
AVT_Type, MEMF_PRIVATE,
AVT_ClearWithValue, 0,
TAG_END);
if (!ipcMsg) {
IExec->DebugPrintF("Failed to allocate IPC message!\n");
return;
}
ipcMsg->watchIndex = watchIndex;
IExec->CopyMem(args, ipcMsg->args, sizeof(ipcMsg->args));
IUtility->Strlcpy(ipcMsg->libName, libName, sizeof(ipcMsg->libName));
IUtility->Strlcpy(ipcMsg->funcName, funcName, sizeof(ipcMsg->funcName));
IExec->CopyMem(paramTypes, ipcMsg->paramTypes, MAX_PARAMS);
// Set task name and address only if taskName is provided
if (taskName) {
IUtility->Strlcpy(ipcMsg->taskName, taskName, sizeof(ipcMsg->taskName));
ipcMsg->taskAddr = taskAddr;
} else {
ipcMsg->taskName[0] = '\0'; // Set to empty string (equivalent to NULL)
ipcMsg->taskAddr = 0;
}
// Copy string parameters
ipcMsg->stringParamCount = 0;
for (int i = 0; i < MAX_PARAMS && paramTypes[i] && ipcMsg->stringParamCount < MAX_STRING_PARAMS; i++) {
if (paramTypes[i] == 's') {
const char *str = (const char *)args[i];
if (str) {
IUtility->Strlcpy(ipcMsg->stringParams[ipcMsg->stringParamCount], str, MAX_STRING_LENGTH);
ipcMsg->args[i] = (uint32)ipcMsg->stringParams[ipcMsg->stringParamCount];
ipcMsg->stringParamCount++;
}
}
}
// Copy tag lists
ipcMsg->tagItemCount = 0;
ipcMsg->tagStringParamCount = 0;
for (int i = 0; i < MAX_PARAMS && paramTypes[i]; i++) {
if (paramTypes[i] == 't') {
struct TagItem *tags = (struct TagItem *)args[i];
if (tags) {
int tagCount = 0;
int moreCount = 0;
while (tags[tagCount].ti_Tag != TAG_END && tags[tagCount].ti_Tag != TAG_DONE &&
tagCount < MAX_TAG_ITEMS && ipcMsg->tagItemCount < MAX_TAG_ITEMS &&
moreCount < 10) {
if (tags[tagCount].ti_Tag == TAG_IGNORE) {
tagCount++;
continue;
}
if (tags[tagCount].ti_Tag == TAG_MORE) {
if (tags[tagCount].ti_Data && moreCount < 10) {
tags = (struct TagItem *)tags[tagCount].ti_Data;
tagCount = 0;
moreCount++;
continue;
}
break;
}
if (tags[tagCount].ti_Tag == TAG_SKIP) {
uint32 skipCount = tags[tagCount].ti_Data;
tagCount += skipCount + 1;
if (tagCount >= MAX_TAG_ITEMS) break;
continue;
}
// Check if the tag is a string type
const struct TagInfo *info = findTagInfoForTag(tags[tagCount].ti_Tag, libName);
if (info && info->Type == 's' && tags[tagCount].ti_Data &&
ipcMsg->tagStringParamCount < MAX_TAG_STRING_PARAMS) {
// Copy string to tagStringParams
IUtility->Strlcpy(ipcMsg->tagStringParams[ipcMsg->tagStringParamCount],
(const char *)tags[tagCount].ti_Data, MAX_STRING_LENGTH);
ipcMsg->tagItems[ipcMsg->tagItemCount].ti_Tag = tags[tagCount].ti_Tag;
ipcMsg->tagItems[ipcMsg->tagItemCount].ti_Data = (uint32)ipcMsg->tagStringParams[ipcMsg->tagStringParamCount];
ipcMsg->tagStringParamCount++;
} else {
// Copy tag as-is
ipcMsg->tagItems[ipcMsg->tagItemCount] = tags[tagCount];
}
ipcMsg->tagItemCount++;
tagCount++;
if (ipcMsg->tagItemCount >= MAX_TAG_ITEMS) break;
}
if (ipcMsg->tagItemCount > 0) {
if (ipcMsg->tagItemCount < MAX_TAG_ITEMS) {
ipcMsg->tagItems[ipcMsg->tagItemCount].ti_Tag = TAG_END;
ipcMsg->tagItemCount++;
}
ipcMsg->args[i] = (uint32)ipcMsg->tagItems;
}
}
}
}
ipcMsg->msg.mn_Node.ln_Type = NT_MESSAGE;
ipcMsg->msg.mn_Length = sizeof(struct IPCMessage);
ipcMsg->msg.mn_ReplyPort = NULL;
IExec->PutMsg(ipcPort, (struct Message *)ipcMsg);
}
And then, after I copy it all, I have to reparse and print it, so it's like double the work... But for now I'm facing another problem: 64-bit arguments for some dos.library functions. The issue is: Currently, all my patching code, wrappers for functions, etc., are using uint32/int32. That's everywhere, and all arguments are treated like this too (bytes, words, etc., are treated as longs, so int32, no problems there; strings and pointers fit into int32 as well). But then, dos.library has six functions that allow some arguments to be int64:
watch=dos,ChangeFilePosition,file=%lp,position=%ld,offset=%ld // file (BPTR), position (int64), offset (int32)
watch=dos,ChangeFileSize,fh=%lp,pos=%ld,mode=%ld // fh (BPTR), pos (int64), mode (int32)
watch=dos,DoPkt64,sendport=%lp,type=%ld,arg1=%ld,arg2=%ld,arg3=%ld,arg4=%ld,arg5=%ld // sendport (struct MsgPort *), type (int32), arg1 (int32), arg2 (int64), arg3 (int32), arg4 (int32), arg5 (int64)
watch=dos,PRIVATEDoPkt64,sendport=%lp,type=%ld,arg1=%ld,arg2=%ld,arg3=%ld,arg4=%ld,arg5=%ld // sendport (struct MsgPort *), type (int32), arg1 (int32), arg2 (int64), arg3 (int32), arg4 (int32), arg5 (int64)
watch=dos,LockRecord,fh=%lp,offset=%ld,length=%ld,mode=%ld,timeout=%ld // fh (BPTR), offset (int64), length (int64), mode (uint32), timeout (uint32)
watch=dos,UnLockRecord,fh=%lp,offset=%ld,length=%ld // fh (BPTR), offset (int64), length (int64)
Now, if I patch those functions with my generic patch, which expects all arguments to be int32, I'll just get bugs because an int64 takes up two int32 slots, causing memory shifts, crashes, and other issues. I see that I need to handle int64 as two int32s in all cases, but that means changing GenericPatch, SendIPCMessage, and the logger to always skip two int32s when encountering an int64, and it’s starting to feel like a mess. If I change everything in the code (wrappers, GenericPatch, etc.) to use int64, I’ll run into problems with int32 arguments for the same reasons. So, for now, I’m thinking about how to solve this one...
|
|
|
|
Re: Snork: New Tracing Tool for AmigaOS 4
|
|
Just popping in 
|
@kas1e Quote: The question i had now , is it correct way of doing things. I mean, for speed and for being correct at all.
I've been thinking about this, and since no one else has jumped in, here are my thoughts. Typically, your current approach -- doing as little as possible in the patch, and postponing the formatting and output to Snork itself -- is the recommended way to handle such things. But I wonder if in this case your original approach -- doing everything, including the DebugPrintF(), in the patch -- isn't a better idea. One drawback to the current approach is that logging the function call is asynchronous to the function call itself- by the time Snork gets the message and outputs the log, the call has already occurred. So if the call crashes due to a bad argument, the crash occurs before the call can be logged (and if the crash takes down the system, the log will never be written). A bigger problem comes up when you start logging exec.library calls. I presume you allocate memory in the patch to hold all the copies of arguments, and memory allocation can break a Forbid() that might be in effect when Exec is called. It looks like that can be prevented by using the AVT_Wait, FALSE tag with AllocVecTags(). An even bigger problem is that some exec.library calls may be made from interrupts, and memory allocation can't be done from within an interrupt. (I'd guess that TypeOfMem() isn't safe to use from an interrupt, either.) Calling DebugPrintF() from within the patch eliminates both of those problems, while also making the logging synchronous to the function calls. And there's no need to copy anything except strings (where you're also filtering out unprintable characters), and those could be buffered on the stack (though you're using the caller's stack, so you have to be careful how much you use). As far as I'm aware, there's no public information on the internal workings of DebugPrintF(). But given its intended purpose, I'd speculate that it depends as little as possible on the rest of the system (and presumably is okay to use from within an interrupt), and likely writes directly to the serial port (in SERIAL mode) with no buffering, and so doesn't return until the entire string has been sent. If this is in fact the case it will be slow (especially when logging a tag list), as it takes 87 us for every character written at 115.2 kbps (it should be much faster if writing to the debug buffer or if using Sashimi). But the advantages of doing it this way may outweigh the reduced speed.
|
|
|
|
Re: X5000 maybe dying :(
|
Posted on: 6/28 23:20
#23
|
Just popping in 
|
@daveyw Okay, it's winter where you are, but here in Switzerland, we're baked! He might have caught a cold  My fan is a Gelid Silent 6.
|
|
|
|
Re: X5000 maybe dying :(
|
Posted on: 6/28 22:46
#24
|
Just popping in 
|
@daveyw
Thermal paste dries over years. I would clean old away ant put new good quality thermal paste there.
|
Peg2 1GHz G4, 1Gb mem, Radeon 9250
|
|
|
Re: X5000 maybe dying :(
|
Posted on: 6/28 22:43
#25
|
Not too shy to talk 
|
@skynet
5020. I've had it since 2017.
I live in the Southern Hemisphere, its winter right now, although my office is reasonably pleasant temperature, but certainly nowhere near 31! Probably not quite 20.
Yeah, 76 does sound high. Maybe because of your high room temperature? Do you know which fan you have? I have the Gelid Silence that most of the X5000s from Amigakit shipped with.
|
|
|
|
Re: X5000 maybe dying :(
|
Posted on: 6/28 21:03
#26
|
Just popping in 
|
Hi daveyw,
Which model do you have, 5020 or 5040?
I've had a 5040 for a year now.
Out of curiosity and in relation to your problem, I checked my processor temperature and it's at 76 degrees Celsius.
I still find it high for my CPU.
I don't really have any idea why your problem is happening; maybe it's due to the heat?
I currently have 31 degrees in my office with a small fan and all the windows open, but no air.
I hope it's nothing serious.
|
|
|
|
Re: DumbPad v03
|
Posted on: 6/28 20:55
#27
|
Just can't stay away 
|
@Maijestro
ok. that's another thing. D&D on AmiDock works if program has ReadArgs() IIRC it's working on.
|
|
|
|
X5000 maybe dying :(
|
Posted on: 6/28 19:57
#28
|
Not too shy to talk 
|
I was work on a project on Friday, not run anything too demanding, when suddenly I noticed a CPU temperature alert. CPU was running 98 degrees!
I powered off and let it cool for a while, then unplugged everything and powered it up lying on its side with the case open to check the CPU fan. It seemed fine.
Plugged everything back in and switched on again. Uboot came up, but OS wouldn't boot. The splash screen sloooowly faded up and then froze.
Left it to cool even longer, then tried again. This time it booted, although again there was the very slow fade up on the splash screen. CPU temperature slowly rose to 58 degrees. I did a backup and powered off.
According to the CPU temp docky, CPU fan speed is 30%. Is there any way to increase this?
|
|
|
|
Re: DumbPad v03
|
Posted on: 6/28 18:12
#29
|
Just can't stay away 
|
@kas1e Quote: kas1e wrote:@Maijestro D&D were added in v0.2, check release notes :) And yeah, i working on, just not ready for next beta Sorry, I expressed myself incorrectly, I meant Drag&Drop via AmiDock which does not yet work with the latest version 0.3.
|
MacStudio ARM M1 Max Qemu//Pegasos2 AmigaOs4.1 FE / AmigaOne x5000/40 AmigaOs4.1 FE
|
|
|
Re: DumbPad v03
|
Posted on: 6/28 17:57
#30
|
Home away from home 
|
@Maijestro D&D were added in v0.2, check release notes :) And yeah, i working on, just not ready for next beta
|
|
|
|
Re: DumbPad v03
|
Posted on: 6/28 17:28
#31
|
Just can't stay away 
|
|
|
|
|
Re: DumbPad v03
|
Posted on: 6/28 17:02
#32
|
Just can't stay away 
|
@kas1e
I'm not sure if I may have missed it, but did you already have drag and drop support added to DumpPad?
Hopefully you will continue to work on this great editor.
|
MacStudio ARM M1 Max Qemu//Pegasos2 AmigaOs4.1 FE / AmigaOne x5000/40 AmigaOs4.1 FE
|
|
|
Re: Introducing the Rear Window blog
|
Posted on: 6/28 13:17
#33
|
Site Builder 
|
@trixie I enjoyed reading your article. And I agree with the majority of what you wrote and the way of thinking.
But, this is the best approach for developers and people who want to dive deeper in the OS. For plain users, and we have observed that happening, the whole situation seems frustrating and they leave the community. There is a need to keep a healthy and productive environment for people to feel that things are moving forward. I just hope that the number of people who would care about the survival and expandability of the platform will increase every year.
|
|
|
|
Re: Introducing the Rear Window blog
|
|
Home away from home 
|
@trixie Quote: Now on the Rear Window blog, my personal manifesto for the summer. Enjoy reading!
That's how I think for years, keeping me away from being disappointed by anything. We use what we already have, and if there are updates - cool, if not, I know what I do and with what. Waiting for anything from leaders or hoping for any promises is the way to the trap. Let them do what they think and can do, but it shouldn't reflect on you in any case.
|
|
|
|
Re: Bootarguments for Qemu AmigaOne install on Mac M1
|
Posted on: 6/27 20:24
#35
|
Just can't stay away 
|
@johnfante
yep, there still some issues, 'cos server(s) where updated. Hope they will fixed ASAP.
|
|
|
|
Re: Snork: New Tracing Tool for AmigaOS 4
|
Posted on: 6/27 19:26
#36
|
Home away from home 
|
@joerg Quote: to add support for international chars, for example the default ISO 8859-15 ones. Unprintable control chars on AmigaOS, in any supported 8 bit charset, are only 0-31 and 127-159.
Good catch , thanks ! Btw, what is the best way to follow if we need to parse data in a patch ? At fist, i just doing simple parsing inside of the patch, and then print it before calling original function. Then after , i add some simple IPC via PutMsg() (from patch) /GetMsg() (in main). At first i tried to simple send what i have to the main, but find out that strings and other data simple died offten (because patch is done, memory changes, but i tried to handle it in the main which is point on whatever else). Because of that i had to copy in the patch before putmsg whole set : libname, functionname, doing findtaks(null), copy strings and tags, and then send this instead. For copy i use IExec->CopyMem/IUtility->Strlcpy (that for libname, funcname and strings), and for tags i simple do simple loop copy. The question i had now , is it correct way of doing things. I mean, for speed and for being correct at all. As i doing dynamic copy for each patching function, i do not need locks and mutexes, but not sure shouldn't i somehow protect it or not ?
Edited by kas1e on 2025/6/27 19:58:44
|
|
|
|
Re: Bootarguments for Qemu AmigaOne install on Mac M1
|
Posted on: 6/27 16:55
#37
|
Just popping in 
|
@jabirulo
Thank you! That is the version I am running.
Think this is some kind of server error.
|
|
|
|
Re: Snork: New Tracing Tool for AmigaOS 4
|
Posted on: 6/27 15:00
#39
|
Home away from home 
|
@msteed Quote: Of course, if the string pointer is invalid the function you're calling will probably cause a DSI itself as soon as you call it. Still, there's some value to Snork not causing the DSI, even if there's going to be one an instant later anyway. Some functions may work with invalid string pointers, depending on other arguments the string pointer may not be used at all by the function itself and if it isn't accessed there wont be a DSI. But Snork would cause a DSI trying to print it.
|
|
|
|
Re: Snork: New Tracing Tool for AmigaOS 4
|
Posted on: 6/27 14:34
#40
|
Home away from home 
|
@kas1e Quote:
strncpy(output, "NULL", output_size - 1);
output[output_size - 1] = '\0';
= strlcpy(output, "NULL", output_size); strncpy() and strncat() should be replaced by strlcpy() and strlcat(). Quote:
} else if (input[i] >= 32 && input[i] <= 126) {
output[j++] = input[i];
Replace by
} else if ((input[i] >= 32 && input[i] <= 126) || (input[i] >= 160)) {
to add support for international chars, for example the default ISO 8859-15 ones. Unprintable control chars on AmigaOS, in any supported 8 bit charset, are only 0-31 and 127-159.
|
|
|
|